Home | History | Annotate | Download | only in extensions
      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 "chrome/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 
    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 
    159 ExtensionInstallPromptExperiment::ExtensionInstallPromptExperiment(
    160     unsigned int group_id, unsigned int flags)
    161     : group_id_(group_id),
    162       flags_(flags) {
    163 }
    164 
    165 ExtensionInstallPromptExperiment::~ExtensionInstallPromptExperiment() {
    166 }
    167 
    168 // static
    169 ExtensionInstallPromptExperiment*
    170     ExtensionInstallPromptExperiment::ControlGroup() {
    171   return new ExtensionInstallPromptExperiment(0, kGroupFlags[0]);
    172 }
    173 
    174 // static
    175 ExtensionInstallPromptExperiment*
    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 
    192 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 
    197 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 
    202 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 
    207 bool ExtensionInstallPromptExperiment::text_only() const {
    208   return (flags_ & TEXT_ONLY) != 0;
    209 }
    210 
    211 bool ExtensionInstallPromptExperiment::ShouldHighlightText(
    212     const base::string16& message) const {
    213   return (flags_ & SHOULD_HIGHLIGHT_TEXT) != 0 && IsImportantWarning(message);
    214 }
    215 
    216 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 
    223 bool ExtensionInstallPromptExperiment::show_details_link() const {
    224   return (flags_ & SHOULD_SHOW_DETAILS_LINK) != 0;
    225 }
    226 
    227 bool ExtensionInstallPromptExperiment::show_checkboxes() const {
    228   return (flags_ & SHOULD_SHOW_CHECKBOXES) != 0;
    229 }
    230 
    231 bool ExtensionInstallPromptExperiment::should_show_expandable_permission_list()
    232     const {
    233   return (flags_ & EXPANDABLE_PERMISSION_LIST) != 0;
    234 }
    235 
    236 bool ExtensionInstallPromptExperiment::should_show_inline_explanations() const {
    237   return (flags_ & INLINE_EXPLANATIONS) != 0;
    238 }
    239 
    240 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