• 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 "base/basictypes.h"
6 #include "base/logging.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/extensions/extension_install_prompt_experiment.h"
12 #include "grit/generated_resources.h"
13 #include "ui/base/l10n/l10n_util.h"
14 
15 namespace {
16 
17 const char kExperimentName[] = "ExtensionPermissionDialog";
18 const char kGroupPrefix[] = "Group";
19 
20 // Flags for groups. Not all combinations make sense.
21 // Refer to the UI screens at http://goo.gl/f2KzPj for those that do.
22 enum GroupFlag {
23   // No changes (Control group).
24   NONE = 0,
25   // Indicates that the experiment is text only. A text only experiment
26   // only adds an explanation text at the bottom of the permission dialog and
27   // modifies the text on accept/cancel buttons.
28   TEXT_ONLY = 1 << 0,
29   // Indicates that the experiment shows inline explanations for permissions.
30   INLINE_EXPLANATIONS = 1 << 1,
31   // Indicates that the experiment highlights permission text color.
32   SHOULD_HIGHLIGHT_TEXT = 1 << 2,
33   // Indicates that the experiment highlights permission text background.
34   SHOULD_HIGHLIGHT_BACKGROUND = 1 << 3,
35   // Indicates that the experiment highlights all permissions.
36   SHOULD_HIGHLIGHT_ALL_PERMISSIONS = 1 << 4,
37   // Indicates that the experiment puts a "show details" link in the UI.
38   SHOULD_SHOW_DETAILS_LINK = 1 << 5,
39   // Indicates that the experiment hides the permissions by default and the list
40   // can be expanded.
41   EXPANDABLE_PERMISSION_LIST = 1 << 6,
42   // Indicates that the experiment shows checkboxes for each permission.
43   SHOULD_SHOW_CHECKBOXES = 1 << 7
44 };
45 
46 // Flags for the actual experiment groups. These flags define what kind of
47 // UI changes each experiment group does. An experiment group may change
48 // multiple aspects of the extension install dialog  (e.g. one of the groups
49 // show a details link and inline explanations for permissions). The control
50 // group doesn't change the UI. Text only groups add a text warning to the UI,
51 // with the text changing depending on the group number. Groups with inline
52 // explanations show detailed explanations for a subset of permissions. Some
53 // groups highlight the foreground or the background of permission texts.
54 // The flags reflect the UI screens at http://goo.gl/f2KzPj.
55 const unsigned int kGroupFlags[] = {
56   // Control group doesn't change the UI.
57   NONE,
58   // Adds "Do you trust this extension to use these privileges safely" text.
59   TEXT_ONLY,
60   // Adds "Extension can be malicious" text.
61   TEXT_ONLY,
62   // Adds "Are you sure you want to install" text.
63   TEXT_ONLY,
64   // Adds "Make sure these privileges make sense for this extension" text.
65   TEXT_ONLY,
66   // Adds "Do you trust this extension to perform these actions" text.
67   TEXT_ONLY,
68   // Adds inline explanations displayed by default.
69   INLINE_EXPLANATIONS,
70   // Adds expandable inline explanations with a "Show Details" link.
71   SHOULD_SHOW_DETAILS_LINK | INLINE_EXPLANATIONS,
72   // Adds expandable permission list with a "Show Permissions" link.
73   SHOULD_SHOW_DETAILS_LINK | EXPANDABLE_PERMISSION_LIST,
74   // Highlights text for risky permissions.
75   SHOULD_HIGHLIGHT_TEXT,
76   // Highlights background for risky permissions.
77   SHOULD_HIGHLIGHT_BACKGROUND,
78   // Highlights background for all permissions
79   SHOULD_HIGHLIGHT_BACKGROUND | SHOULD_HIGHLIGHT_ALL_PERMISSIONS,
80   // Displays checkboxes for all permissions.
81   SHOULD_SHOW_CHECKBOXES
82 };
83 
84 const size_t kGroupCount = arraysize(kGroupFlags);
85 
86 // Parameters for text only experiments.
87 const struct TextParams {
88   int text_id;
89   int ok_text_id;
90   int cancel_text_id;
91 } kTextParams[] = {
92   {
93     IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION1,
94     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_TRUST,
95     IDS_CANCEL,
96   },
97   {
98     IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION2,
99     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_YES,
100     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
101   },
102   {
103     IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION3,
104     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_SURE,
105     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
106   },
107   {
108     IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION4,
109     IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
110     IDS_CANCEL
111   },
112   {
113     IDS_EXTENSION_PROMPT_EXPERIMENT_EXPLANATION5,
114     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_TRUST2,
115     IDS_EXTENSION_PROMPT_EXPERIMENT_INSTALL_BUTTON_NOPE
116   }
117 };
118 
119 // Permission warnings in this list have inline explanation texts.
120 const struct PermissionExplanations {
121   int warning_msg_id;
122   int extra_explanation_id;
123 } kPermissionExplanations[] = {
124   {
125     IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
126     IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS_EXPLANATION
127   },
128   {
129     IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
130     IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_EXPLANATION
131   }
132 };
133 
134 // Permission warnings in this list are going to be highlighted.
135 // Note that the matching is done by string comparison, so this list must not
136 // contain any dynamic strings (e.g. permission for 3 hosts with the host list).
137 const int kHighlightedWarnings[] = {
138   IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
139   IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
140   IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
141   IDS_EXTENSION_PROMPT_WARNING_CONTENT_SETTINGS,
142   IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE,
143   IDS_EXTENSION_PROMPT_WARNING_INPUT,
144   IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
145   IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ,
146   IDS_EXTENSION_PROMPT_WARNING_DEBUGGER
147 };
148 
IsImportantWarning(const base::string16 & message)149 bool IsImportantWarning(const base::string16& message) {
150   for (size_t i = 0; i < arraysize(kHighlightedWarnings); ++i) {
151     if (message == l10n_util::GetStringUTF16(kHighlightedWarnings[i]))
152       return true;
153   }
154   return false;
155 }
156 
157 }  // namespace
158 
ExtensionInstallPromptExperiment(unsigned int group_id,unsigned int flags)159 ExtensionInstallPromptExperiment::ExtensionInstallPromptExperiment(
160     unsigned int group_id, unsigned int flags)
161     : group_id_(group_id),
162       flags_(flags) {
163 }
164 
~ExtensionInstallPromptExperiment()165 ExtensionInstallPromptExperiment::~ExtensionInstallPromptExperiment() {
166 }
167 
168 // static
169 ExtensionInstallPromptExperiment*
ControlGroup()170     ExtensionInstallPromptExperiment::ControlGroup() {
171   return new ExtensionInstallPromptExperiment(0, kGroupFlags[0]);
172 }
173 
174 // static
175 ExtensionInstallPromptExperiment*
Find()176     ExtensionInstallPromptExperiment::Find() {
177   base::FieldTrial* trial = base::FieldTrialList::Find(kExperimentName);
178   // Default is control group.
179   unsigned int group_id = 0;
180   if (trial) {
181     std::vector<std::string> tokens;
182     base::SplitString(trial->group_name().c_str(), '_', &tokens);
183     if (tokens.size() == 2 && tokens[0] == kGroupPrefix) {
184       base::StringToUint(tokens[1], &group_id);
185       if (group_id >= kGroupCount)
186         group_id = 0;
187     }
188   }
189   return new ExtensionInstallPromptExperiment(group_id, kGroupFlags[group_id]);
190 }
191 
GetExplanationText() const192 base::string16 ExtensionInstallPromptExperiment::GetExplanationText() const {
193   DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
194   return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].text_id);
195 }
196 
GetOkButtonText() const197 base::string16 ExtensionInstallPromptExperiment::GetOkButtonText() const {
198   DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
199   return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].ok_text_id);
200 }
201 
GetCancelButtonText() const202 base::string16 ExtensionInstallPromptExperiment::GetCancelButtonText() const {
203   DCHECK(group_id_ > 0 && group_id_ - 1 < arraysize(kTextParams));
204   return l10n_util::GetStringUTF16(kTextParams[group_id_ - 1].cancel_text_id);
205 }
206 
text_only() const207 bool ExtensionInstallPromptExperiment::text_only() const {
208   return (flags_ & TEXT_ONLY) != 0;
209 }
210 
ShouldHighlightText(const base::string16 & message) const211 bool ExtensionInstallPromptExperiment::ShouldHighlightText(
212     const base::string16& message) const {
213   return (flags_ & SHOULD_HIGHLIGHT_TEXT) != 0 && IsImportantWarning(message);
214 }
215 
ShouldHighlightBackground(const base::string16 & message) const216 bool ExtensionInstallPromptExperiment::ShouldHighlightBackground(
217     const base::string16& message) const {
218   return (flags_ & SHOULD_HIGHLIGHT_BACKGROUND) != 0 &&
219       ((flags_ & SHOULD_HIGHLIGHT_ALL_PERMISSIONS) != 0 ||
220       IsImportantWarning(message));
221 }
222 
show_details_link() const223 bool ExtensionInstallPromptExperiment::show_details_link() const {
224   return (flags_ & SHOULD_SHOW_DETAILS_LINK) != 0;
225 }
226 
show_checkboxes() const227 bool ExtensionInstallPromptExperiment::show_checkboxes() const {
228   return (flags_ & SHOULD_SHOW_CHECKBOXES) != 0;
229 }
230 
should_show_expandable_permission_list() const231 bool ExtensionInstallPromptExperiment::should_show_expandable_permission_list()
232     const {
233   return (flags_ & EXPANDABLE_PERMISSION_LIST) != 0;
234 }
235 
should_show_inline_explanations() const236 bool ExtensionInstallPromptExperiment::should_show_inline_explanations() const {
237   return (flags_ & INLINE_EXPLANATIONS) != 0;
238 }
239 
GetInlineExplanation(const base::string16 & message) const240 base::string16 ExtensionInstallPromptExperiment::GetInlineExplanation(
241     const base::string16& message) const {
242   for (size_t i = 0; i < arraysize(kPermissionExplanations); ++i) {
243     if (message == l10n_util::GetStringUTF16(
244         kPermissionExplanations[i].warning_msg_id)) {
245       return l10n_util::GetStringUTF16(
246           kPermissionExplanations[i].extra_explanation_id);
247     }
248   }
249   return base::string16();
250 }
251