Home | History | Annotate | Download | only in extensions
      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 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
      6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/callback.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/files/file_path.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/strings/string16.h"
     16 #include "chrome/browser/extensions/crx_installer_error.h"
     17 #include "chrome/browser/signin/oauth2_token_service.h"
     18 #include "extensions/common/url_pattern.h"
     19 #include "google_apis/gaia/oauth2_mint_token_flow.h"
     20 #include "third_party/skia/include/core/SkBitmap.h"
     21 #include "ui/gfx/image/image.h"
     22 #include "ui/gfx/image/image_skia.h"
     23 #include "ui/gfx/native_widget_types.h"
     24 
     25 class Browser;
     26 class ExtensionInstallUI;
     27 class InfoBarDelegate;
     28 class Profile;
     29 
     30 namespace base {
     31 class DictionaryValue;
     32 class MessageLoop;
     33 }  // namespace base
     34 
     35 namespace content {
     36 class PageNavigator;
     37 class WebContents;
     38 }
     39 
     40 namespace extensions {
     41 class BundleInstaller;
     42 class Extension;
     43 class ExtensionWebstorePrivateApiTest;
     44 class MockGetAuthTokenFunction;
     45 class PermissionSet;
     46 }  // namespace extensions
     47 
     48 // Displays all the UI around extension installation.
     49 class ExtensionInstallPrompt
     50     : public OAuth2MintTokenFlow::Delegate,
     51       public OAuth2TokenService::Consumer,
     52       public base::SupportsWeakPtr<ExtensionInstallPrompt> {
     53  public:
     54   enum PromptType {
     55     UNSET_PROMPT_TYPE = -1,
     56     INSTALL_PROMPT = 0,
     57     INLINE_INSTALL_PROMPT,
     58     BUNDLE_INSTALL_PROMPT,
     59     RE_ENABLE_PROMPT,
     60     PERMISSIONS_PROMPT,
     61     EXTERNAL_INSTALL_PROMPT,
     62     POST_INSTALL_PERMISSIONS_PROMPT,
     63     NUM_PROMPT_TYPES
     64   };
     65 
     66   // Extra information needed to display an installation or uninstallation
     67   // prompt. Gets populated with raw data and exposes getters for formatted
     68   // strings so that the GTK/views/Cocoa install dialogs don't have to repeat
     69   // that logic.
     70   class Prompt {
     71    public:
     72     explicit Prompt(PromptType type);
     73     ~Prompt();
     74 
     75     // Sets the permission list for this prompt.
     76     void SetPermissions(const std::vector<string16>& permissions);
     77     // Sets the permission list details for this prompt.
     78     void SetPermissionsDetails(const std::vector<string16>& details);
     79     void SetInlineInstallWebstoreData(const std::string& localized_user_count,
     80                                       bool show_user_count,
     81                                       double average_rating,
     82                                       int rating_count);
     83     void SetOAuthIssueAdvice(const IssueAdviceInfo& issue_advice);
     84     void SetUserNameFromProfile(Profile* profile);
     85 
     86     PromptType type() const { return type_; }
     87     void set_type(PromptType type) { type_ = type; }
     88 
     89     // Getters for UI element labels.
     90     string16 GetDialogTitle() const;
     91     string16 GetHeading() const;
     92     int GetDialogButtons() const;
     93     bool HasAcceptButtonLabel() const;
     94     string16 GetAcceptButtonLabel() const;
     95     bool HasAbortButtonLabel() const;
     96     string16 GetAbortButtonLabel() const;
     97     string16 GetPermissionsHeading() const;
     98     string16 GetOAuthHeading() const;
     99     string16 GetRetainedFilesHeading() const;
    100     string16 GetRetainedFilesHeadingWithCount() const;
    101 
    102     bool ShouldShowPermissions() const;
    103 
    104     // Getters for webstore metadata. Only populated when the type is
    105     // INLINE_INSTALL_PROMPT.
    106 
    107     // The star display logic replicates the one used by the webstore (from
    108     // components.ratingutils.setFractionalYellowStars). Callers pass in an
    109     // "appender", which will be repeatedly called back with the star images
    110     // that they append to the star display area.
    111     typedef void(*StarAppender)(const gfx::ImageSkia*, void*);
    112     void AppendRatingStars(StarAppender appender, void* data) const;
    113     string16 GetRatingCount() const;
    114     string16 GetUserCount() const;
    115     size_t GetPermissionCount() const;
    116     size_t GetPermissionsDetailsCount() const;
    117     string16 GetPermission(size_t index) const;
    118     string16 GetPermissionsDetails(size_t index) const;
    119     size_t GetOAuthIssueCount() const;
    120     const IssueAdviceInfoEntry& GetOAuthIssue(size_t index) const;
    121     size_t GetRetainedFileCount() const;
    122     string16 GetRetainedFile(size_t index) const;
    123 
    124     // Populated for BUNDLE_INSTALL_PROMPT.
    125     const extensions::BundleInstaller* bundle() const { return bundle_; }
    126     void set_bundle(const extensions::BundleInstaller* bundle) {
    127       bundle_ = bundle;
    128     }
    129 
    130     // Populated for all other types.
    131     const extensions::Extension* extension() const { return extension_; }
    132     void set_extension(const extensions::Extension* extension) {
    133       extension_ = extension;
    134     }
    135 
    136     // May be populated for POST_INSTALL_PERMISSIONS_PROMPT.
    137     void set_retained_files(const std::vector<base::FilePath>& retained_files) {
    138       retained_files_ = retained_files;
    139     }
    140 
    141     const gfx::Image& icon() const { return icon_; }
    142     void set_icon(const gfx::Image& icon) { icon_ = icon; }
    143 
    144    private:
    145     bool ShouldDisplayRevokeFilesButton() const;
    146 
    147     PromptType type_;
    148 
    149     // Permissions that are being requested (may not be all of an extension's
    150     // permissions if only additional ones are being requested)
    151     std::vector<string16> permissions_;
    152     std::vector<string16> details_;
    153 
    154     // Descriptions and details for OAuth2 permissions to display to the user.
    155     // These correspond to permission scopes.
    156     IssueAdviceInfo oauth_issue_advice_;
    157 
    158     // User name to be used in Oauth heading label.
    159     string16 oauth_user_name_;
    160 
    161     // The extension or bundle being installed.
    162     const extensions::Extension* extension_;
    163     const extensions::BundleInstaller* bundle_;
    164 
    165     // The icon to be displayed.
    166     gfx::Image icon_;
    167 
    168     // These fields are populated only when the prompt type is
    169     // INLINE_INSTALL_PROMPT
    170     // Already formatted to be locale-specific.
    171     std::string localized_user_count_;
    172     // Range is kMinExtensionRating to kMaxExtensionRating
    173     double average_rating_;
    174     int rating_count_;
    175 
    176     // Whether we should display the user count (we anticipate this will be
    177     // false if localized_user_count_ represents the number zero).
    178     bool show_user_count_;
    179 
    180     std::vector<base::FilePath> retained_files_;
    181   };
    182 
    183   static const int kMinExtensionRating = 0;
    184   static const int kMaxExtensionRating = 5;
    185 
    186   class Delegate {
    187    public:
    188     // We call this method to signal that the installation should continue.
    189     virtual void InstallUIProceed() = 0;
    190 
    191     // We call this method to signal that the installation should stop, with
    192     // |user_initiated| true if the installation was stopped by the user.
    193     virtual void InstallUIAbort(bool user_initiated) = 0;
    194 
    195    protected:
    196     virtual ~Delegate() {}
    197   };
    198 
    199   // Parameters to show a prompt dialog. Two sets of the
    200   // parameters are supported: either use a parent WebContents or use a
    201   // parent NativeWindow + a PageNavigator.
    202   struct ShowParams {
    203     explicit ShowParams(content::WebContents* contents);
    204     ShowParams(gfx::NativeWindow window, content::PageNavigator* navigator);
    205 
    206     // Parent web contents of the install UI dialog. This can be NULL.
    207     content::WebContents* parent_web_contents;
    208 
    209     // NativeWindow parent and navigator. If initialized using a parent web
    210     // contents, these are derived from it.
    211     gfx::NativeWindow parent_window;
    212     content::PageNavigator* navigator;
    213   };
    214 
    215   typedef base::Callback<void(const ExtensionInstallPrompt::ShowParams&,
    216                               ExtensionInstallPrompt::Delegate*,
    217                               const ExtensionInstallPrompt::Prompt&)>
    218       ShowDialogCallback;
    219 
    220   // Callback to show the default extension install dialog.
    221   // The implementations of this function are platform-specific.
    222   static ShowDialogCallback GetDefaultShowDialogCallback();
    223 
    224   // Creates a dummy extension from the |manifest|, replacing the name and
    225   // description with the localizations if provided.
    226   static scoped_refptr<extensions::Extension> GetLocalizedExtensionForDisplay(
    227       const base::DictionaryValue* manifest,
    228       int flags,  // Extension::InitFromValueFlags
    229       const std::string& id,
    230       const std::string& localized_name,
    231       const std::string& localized_description,
    232       std::string* error);
    233 
    234   // Creates a prompt with a parent web content.
    235   explicit ExtensionInstallPrompt(content::WebContents* contents);
    236 
    237   // Creates a prompt with a profile, a native window and a page navigator.
    238   ExtensionInstallPrompt(Profile* profile,
    239                          gfx::NativeWindow native_window,
    240                          content::PageNavigator* navigator);
    241 
    242   virtual ~ExtensionInstallPrompt();
    243 
    244   ExtensionInstallUI* install_ui() const { return install_ui_.get(); }
    245 
    246   bool record_oauth2_grant() const { return record_oauth2_grant_; }
    247 
    248   content::WebContents* parent_web_contents() const {
    249     return show_params_.parent_web_contents;
    250   }
    251 
    252   // This is called by the bundle installer to verify whether the bundle
    253   // should be installed.
    254   //
    255   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    256   virtual void ConfirmBundleInstall(
    257       extensions::BundleInstaller* bundle,
    258       const extensions::PermissionSet* permissions);
    259 
    260   // This is called by the standalone installer to verify whether the install
    261   // from the webstore should proceed.
    262   //
    263   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    264   virtual void ConfirmStandaloneInstall(Delegate* delegate,
    265                                         const extensions::Extension* extension,
    266                                         SkBitmap* icon,
    267                                         const Prompt& prompt);
    268 
    269   // This is called by the installer to verify whether the installation from
    270   // the webstore should proceed. |show_dialog_callback| is optional and can be
    271   // NULL.
    272   //
    273   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    274   virtual void ConfirmWebstoreInstall(
    275       Delegate* delegate,
    276       const extensions::Extension* extension,
    277       const SkBitmap* icon,
    278       const ShowDialogCallback& show_dialog_callback);
    279 
    280   // This is called by the installer to verify whether the installation should
    281   // proceed. This is declared virtual for testing. |show_dialog_callback| is
    282   // optional and can be NULL.
    283   //
    284   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    285   virtual void ConfirmInstall(Delegate* delegate,
    286                               const extensions::Extension* extension,
    287                               const ShowDialogCallback& show_dialog_callback);
    288 
    289   // This is called by the app handler launcher to verify whether the app
    290   // should be re-enabled. This is declared virtual for testing.
    291   //
    292   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    293   virtual void ConfirmReEnable(Delegate* delegate,
    294                                const extensions::Extension* extension);
    295 
    296   // This is called by the external install alert UI to verify whether the
    297   // extension should be enabled (external extensions are installed disabled).
    298   //
    299   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    300   virtual void ConfirmExternalInstall(
    301       Delegate* delegate,
    302       const extensions::Extension* extension,
    303       const ShowDialogCallback& show_dialog_callback);
    304 
    305   // This is called by the extension permissions API to verify whether an
    306   // extension may be granted additional permissions.
    307   //
    308   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    309   virtual void ConfirmPermissions(Delegate* delegate,
    310                                   const extensions::Extension* extension,
    311                                   const extensions::PermissionSet* permissions);
    312 
    313   // This is called by the extension identity API to verify whether an
    314   // extension can be granted an OAuth2 token.
    315   //
    316   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    317   virtual void ConfirmIssueAdvice(Delegate* delegate,
    318                                   const extensions::Extension* extension,
    319                                   const IssueAdviceInfo& issue_advice);
    320 
    321   // This is called by the app handler launcher to review what permissions the
    322   // extension or app currently has.
    323   //
    324   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    325   virtual void ReviewPermissions(
    326       Delegate* delegate,
    327       const extensions::Extension* extension,
    328       const std::vector<base::FilePath>& retained_file_paths);
    329 
    330   // Installation was successful. This is declared virtual for testing.
    331   virtual void OnInstallSuccess(const extensions::Extension* extension,
    332                                 SkBitmap* icon);
    333 
    334   // Installation failed. This is declared virtual for testing.
    335   virtual void OnInstallFailure(const extensions::CrxInstallerError& error);
    336 
    337  protected:
    338   friend class extensions::ExtensionWebstorePrivateApiTest;
    339   friend class extensions::MockGetAuthTokenFunction;
    340   friend class WebstoreStartupInstallUnpackFailureTest;
    341 
    342   // Whether or not we should record the oauth2 grant upon successful install.
    343   bool record_oauth2_grant_;
    344 
    345  private:
    346   friend class GalleryInstallApiTestObserver;
    347 
    348   // Sets the icon that will be used in any UI. If |icon| is NULL, or contains
    349   // an empty bitmap, then a default icon will be used instead.
    350   void SetIcon(const SkBitmap* icon);
    351 
    352   // ImageLoader callback.
    353   void OnImageLoaded(const gfx::Image& image);
    354 
    355   // Starts the process of showing a confirmation UI, which is split into two.
    356   // 1) Set off a 'load icon' task.
    357   // 2) Handle the load icon response and show the UI (OnImageLoaded).
    358   void LoadImageIfNeeded();
    359 
    360   // Starts fetching warnings for OAuth2 scopes, if there are any.
    361   void FetchOAuthIssueAdviceIfNeeded();
    362 
    363   // OAuth2TokenService::Consumer implementation:
    364   virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
    365                                  const std::string& access_token,
    366                                  const base::Time& expiration_time) OVERRIDE;
    367   virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
    368                                  const GoogleServiceAuthError& error) OVERRIDE;
    369 
    370   // OAuth2MintTokenFlow::Delegate implementation:
    371   virtual void OnIssueAdviceSuccess(
    372       const IssueAdviceInfo& issue_advice) OVERRIDE;
    373   virtual void OnMintTokenFailure(
    374       const GoogleServiceAuthError& error) OVERRIDE;
    375 
    376   // Shows the actual UI (the icon should already be loaded).
    377   void ShowConfirmation();
    378 
    379   base::MessageLoop* ui_loop_;
    380 
    381   // The extensions installation icon.
    382   SkBitmap icon_;
    383 
    384   // The extension we are showing the UI for, if type is not
    385   // BUNDLE_INSTALL_PROMPT.
    386   const extensions::Extension* extension_;
    387 
    388   // The bundle we are showing the UI for, if type BUNDLE_INSTALL_PROMPT.
    389   const extensions::BundleInstaller* bundle_;
    390 
    391   // The permissions being prompted for.
    392   scoped_refptr<const extensions::PermissionSet> permissions_;
    393 
    394   // The object responsible for doing the UI specific actions.
    395   scoped_ptr<ExtensionInstallUI> install_ui_;
    396 
    397   // Parameters to show the confirmation UI.
    398   ShowParams show_params_;
    399 
    400   // The delegate we will call Proceed/Abort on after confirmation UI.
    401   Delegate* delegate_;
    402 
    403   // A pre-filled prompt.
    404   Prompt prompt_;
    405 
    406   scoped_ptr<OAuth2TokenService::Request> login_token_request_;
    407   scoped_ptr<OAuth2MintTokenFlow> token_flow_;
    408 
    409   // Used to show the confirm dialog.
    410   ShowDialogCallback show_dialog_callback_;
    411 };
    412 
    413 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
    414