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
25class Browser;
26class ExtensionInstallUI;
27class InfoBarDelegate;
28class Profile;
29
30namespace base {
31class DictionaryValue;
32class MessageLoop;
33}  // namespace base
34
35namespace content {
36class PageNavigator;
37class WebContents;
38}
39
40namespace extensions {
41class BundleInstaller;
42class Extension;
43class ExtensionWebstorePrivateApiTest;
44class MockGetAuthTokenFunction;
45class PermissionSet;
46}  // namespace extensions
47
48// Displays all the UI around extension installation.
49class 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