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_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_
6 #define CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_
7 
8 #include <stdint.h>
9 
10 #include <map>
11 #include <set>
12 #include <string>
13 #include <vector>
14 
15 #include "base/compiler_specific.h"
16 #include "base/macros.h"
17 #include "base/scoped_observer.h"
18 #include "base/strings/string16.h"
19 #include "build/build_config.h"
20 #include "chrome/app/vector_icons/vector_icons.h"
21 #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h"
22 #include "chrome/common/custom_handlers/protocol_handler.h"
23 #include "components/blocked_content/url_list_manager.h"
24 #include "components/content_settings/browser/page_specific_content_settings.h"
25 #include "components/content_settings/core/common/content_settings.h"
26 #include "components/content_settings/core/common/content_settings_types.h"
27 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/image/image.h"
30 #include "url/gurl.h"
31 
32 class ContentSettingBubbleModelDelegate;
33 class Profile;
34 class ProtocolHandlerRegistry;
35 
36 namespace content {
37 class WebContents;
38 }
39 
40 namespace rappor {
41 class RapporServiceImpl;
42 }
43 
44 namespace ui {
45 class Event;
46 }
47 
48 // The hierarchy of bubble models:
49 //
50 // ContentSettingBubbleModel                  - base class
51 //   ContentSettingSimpleBubbleModel             - single content setting
52 //     ContentSettingMixedScriptBubbleModel        - mixed script
53 //     ContentSettingRPHBubbleModel                - protocol handlers
54 //     ContentSettingPluginBubbleModel             - plugins
55 //     ContentSettingSingleRadioGroup              - radio group
56 //       ContentSettingCookiesBubbleModel            - cookies
57 //       ContentSettingPopupBubbleModel              - popups
58 //       ContentSettingFramebustBlockBubbleModel     - blocked frame busting
59 //   ContentSettingMediaStreamBubbleModel        - media (camera and mic)
60 //   ContentSettingSubresourceFilterBubbleModel  - filtered subresources
61 //   ContentSettingDownloadsBubbleModel          - automatic downloads
62 //   ContentSettingNotificationsBubbleModel      - notifications
63 
64 // Forward declaration necessary for downcasts.
65 class ContentSettingSimpleBubbleModel;
66 class ContentSettingMediaStreamBubbleModel;
67 class ContentSettingSubresourceFilterBubbleModel;
68 class ContentSettingDownloadsBubbleModel;
69 class ContentSettingFramebustBlockBubbleModel;
70 class ContentSettingNotificationsBubbleModel;
71 
72 // This model provides data for ContentSettingBubble, and also controls
73 // the action triggered when the allow / block radio buttons are triggered.
74 class ContentSettingBubbleModel {
75  public:
76   typedef ContentSettingBubbleModelDelegate Delegate;
77 
78   struct ListItem {
79     ListItem(const gfx::VectorIcon* image,
80              const base::string16& title,
81              const base::string16& description,
82              bool has_link,
83              bool has_blocked_badge,
84              int32_t item_id);
85     ListItem(const ListItem& other);
86     ListItem& operator=(const ListItem& other);
87     const gfx::VectorIcon* image;
88     base::string16 title;
89     base::string16 description;
90     bool has_link;
91     bool has_blocked_badge;
92     int32_t item_id;
93   };
94   typedef std::vector<ListItem> ListItems;
95 
96   class Owner {
97    public:
OnListItemAdded(const ListItem & item)98     virtual void OnListItemAdded(const ListItem& item) {}
OnListItemRemovedAt(int index)99     virtual void OnListItemRemovedAt(int index) {}
100     virtual int GetSelectedRadioOption() = 0;
101 
102    protected:
103     virtual ~Owner() = default;
104   };
105 
106   typedef std::vector<base::string16> RadioItems;
107   struct RadioGroup {
108     RadioGroup();
109     ~RadioGroup();
110 
111     GURL url;
112     RadioItems radio_items;
113     int default_item;
114 
115     // Whether the user can control this radio group. False if controlled by
116     // policy, etc.
117     bool user_managed = true;
118   };
119 
120   struct DomainList {
121     DomainList();
122     DomainList(const DomainList& other);
123     ~DomainList();
124 
125     base::string16 title;
126     std::set<std::string> hosts;
127   };
128 
129   struct MediaMenu {
130     MediaMenu();
131     MediaMenu(const MediaMenu& other);
132     ~MediaMenu();
133 
134     base::string16 label;
135     blink::MediaStreamDevice default_device;
136     blink::MediaStreamDevice selected_device;
137     bool disabled;
138   };
139   typedef std::map<blink::mojom::MediaStreamType, MediaMenu> MediaMenuMap;
140 
141   enum class ManageTextStyle {
142     // No Manage button or checkbox is displayed.
143     kNone,
144     // Manage text is displayed as a non-prominent button.
145     kButton,
146     // Manage text is used as a checkbox title.
147     kCheckbox,
148   };
149 
150   struct BubbleContent {
151     BubbleContent();
152     ~BubbleContent();
153 
154     base::string16 title;
155     base::string16 message;
156     ListItems list_items;
157     RadioGroup radio_group;
158     std::vector<DomainList> domain_lists;
159     base::string16 custom_link;
160     bool custom_link_enabled = false;
161     base::string16 manage_text;
162     ManageTextStyle manage_text_style = ManageTextStyle::kButton;
163     MediaMenuMap media_menus;
164     bool show_learn_more = false;
165     base::string16 done_button_text;
166     base::string16 cancel_button_text;
167 
168    private:
169     DISALLOW_COPY_AND_ASSIGN(BubbleContent);
170   };
171 
172   static const int kAllowButtonIndex;
173 
174   // Creates a bubble model for a particular |content_type|. Note that not all
175   // bubbles fit this description.
176   // TODO(msramek): Move this to ContentSettingSimpleBubbleModel or remove
177   // entirely.
178   static std::unique_ptr<ContentSettingBubbleModel>
179   CreateContentSettingBubbleModel(Delegate* delegate,
180                                   content::WebContents* web_contents,
181                                   ContentSettingsType content_type);
182 
183   virtual ~ContentSettingBubbleModel();
184 
bubble_content()185   const BubbleContent& bubble_content() const { return bubble_content_; }
186 
set_owner(Owner * owner)187   void set_owner(Owner* owner) { owner_ = owner; }
188 
OnListItemClicked(int index,const ui::Event & event)189   virtual void OnListItemClicked(int index, const ui::Event& event) {}
OnCustomLinkClicked()190   virtual void OnCustomLinkClicked() {}
OnManageButtonClicked()191   virtual void OnManageButtonClicked() {}
OnManageCheckboxChecked(bool is_checked)192   virtual void OnManageCheckboxChecked(bool is_checked) {}
OnLearnMoreClicked()193   virtual void OnLearnMoreClicked() {}
OnMediaMenuClicked(blink::mojom::MediaStreamType type,const std::string & selected_device_id)194   virtual void OnMediaMenuClicked(blink::mojom::MediaStreamType type,
195                                   const std::string& selected_device_id) {}
OnDoneButtonClicked()196   virtual void OnDoneButtonClicked() {}
OnCancelButtonClicked()197   virtual void OnCancelButtonClicked() {}
198   // Called by the view code when the bubble is closed
CommitChanges()199   virtual void CommitChanges() {}
200 
201   // TODO(msramek): The casting methods below are only necessary because
202   // ContentSettingBubbleController in the Cocoa UI needs to know the type of
203   // the bubble it wraps. Find a solution that does not require reflection nor
204   // recreating the entire hierarchy for Cocoa UI.
205   // Cast this bubble into ContentSettingSimpleBubbleModel if possible.
206   virtual ContentSettingSimpleBubbleModel* AsSimpleBubbleModel();
207 
208   // Cast this bubble into ContentSettingMediaStreamBubbleModel if possible.
209   virtual ContentSettingMediaStreamBubbleModel* AsMediaStreamBubbleModel();
210 
211   // Cast this bubble into ContentSettingSubresourceFilterBubbleModel
212   // if possible.
213   virtual ContentSettingSubresourceFilterBubbleModel*
214   AsSubresourceFilterBubbleModel();
215 
216   // Cast this bubble into ContentSettingDownloadsBubbleModel if possible.
217   virtual ContentSettingDownloadsBubbleModel* AsDownloadsBubbleModel();
218 
219   // Cast this bubble into ContentSettingFramebustBlockBubbleModel if possible.
220   virtual ContentSettingFramebustBlockBubbleModel*
221   AsFramebustBlockBubbleModel();
222 
223   // Cast this bubble into ContentSettingNotificationsBubbleModel if possible.
224   virtual ContentSettingNotificationsBubbleModel* AsNotificationsBubbleModel();
225 
226   // Sets the Rappor service used for testing.
SetRapporServiceImplForTesting(rappor::RapporServiceImpl * rappor_service)227   void SetRapporServiceImplForTesting(
228       rappor::RapporServiceImpl* rappor_service) {
229     rappor_service_ = rappor_service;
230   }
231 
232  protected:
233   // |web_contents| must outlive this.
234   ContentSettingBubbleModel(Delegate* delegate,
235                             content::WebContents* web_contents);
236 
237   // Should always be non-nullptr.
web_contents()238   content::WebContents* web_contents() const { return web_contents_; }
239   Profile* GetProfile() const;
delegate()240   Delegate* delegate() const { return delegate_; }
selected_item()241   int selected_item() const { return owner_->GetSelectedRadioOption(); }
242 
set_title(const base::string16 & title)243   void set_title(const base::string16& title) { bubble_content_.title = title; }
set_message(const base::string16 & message)244   void set_message(const base::string16& message) {
245     bubble_content_.message = message;
246   }
clear_message()247   void clear_message() { bubble_content_.message.clear(); }
248   void AddListItem(const ListItem& item);
249   void RemoveListItem(int index);
set_radio_group(const RadioGroup & radio_group)250   void set_radio_group(const RadioGroup& radio_group) {
251     bubble_content_.radio_group = radio_group;
252   }
add_domain_list(const DomainList & domain_list)253   void add_domain_list(const DomainList& domain_list) {
254     bubble_content_.domain_lists.push_back(domain_list);
255   }
set_custom_link(const base::string16 & link)256   void set_custom_link(const base::string16& link) {
257     bubble_content_.custom_link = link;
258   }
set_custom_link_enabled(bool enabled)259   void set_custom_link_enabled(bool enabled) {
260     bubble_content_.custom_link_enabled = enabled;
261   }
set_manage_text(const base::string16 & text)262   void set_manage_text(const base::string16& text) {
263     bubble_content_.manage_text = text;
264   }
set_manage_text_style(ManageTextStyle manage_text_style)265   void set_manage_text_style(ManageTextStyle manage_text_style) {
266     bubble_content_.manage_text_style = manage_text_style;
267   }
add_media_menu(blink::mojom::MediaStreamType type,const MediaMenu & menu)268   void add_media_menu(blink::mojom::MediaStreamType type,
269                       const MediaMenu& menu) {
270     bubble_content_.media_menus[type] = menu;
271   }
set_selected_device(const blink::MediaStreamDevice & device)272   void set_selected_device(const blink::MediaStreamDevice& device) {
273     bubble_content_.media_menus[device.type].selected_device = device;
274   }
set_show_learn_more(bool show_learn_more)275   void set_show_learn_more(bool show_learn_more) {
276     bubble_content_.show_learn_more = show_learn_more;
277   }
set_done_button_text(const base::string16 & done_button_text)278   void set_done_button_text(const base::string16& done_button_text) {
279     bubble_content_.done_button_text = done_button_text;
280   }
set_cancel_button_text(const base::string16 & cancel_button_text)281   void set_cancel_button_text(const base::string16& cancel_button_text) {
282     bubble_content_.cancel_button_text = cancel_button_text;
283   }
rappor_service()284   rappor::RapporServiceImpl* rappor_service() const { return rappor_service_; }
285 
286  private:
287   content::WebContents* web_contents_;
288   Owner* owner_;
289   Delegate* delegate_;
290   BubbleContent bubble_content_;
291   // The service used to record Rappor metrics. Can be set for testing.
292   rappor::RapporServiceImpl* rappor_service_;
293 
294   DISALLOW_COPY_AND_ASSIGN(ContentSettingBubbleModel);
295 };
296 
297 // A generic bubble used for a single content setting.
298 class ContentSettingSimpleBubbleModel : public ContentSettingBubbleModel {
299  public:
300   ContentSettingSimpleBubbleModel(Delegate* delegate,
301                                   content::WebContents* web_contents,
302                                   ContentSettingsType content_type);
303 
content_type()304   ContentSettingsType content_type() { return content_type_; }
305 
306   // ContentSettingBubbleModel implementation.
307   ContentSettingSimpleBubbleModel* AsSimpleBubbleModel() override;
308 
309  private:
310   FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest, ManageButtonClicked);
311 
312   // ContentSettingBubbleModel implementation.
313   void SetTitle();
314   void SetMessage();
315   void SetManageText();
316   void OnManageButtonClicked() override;
317   void SetCustomLink();
318   void OnCustomLinkClicked() override;
319 
320   ContentSettingsType content_type_;
321 
322   DISALLOW_COPY_AND_ASSIGN(ContentSettingSimpleBubbleModel);
323 };
324 
325 // RPH stands for Register Protocol Handler.
326 class ContentSettingRPHBubbleModel : public ContentSettingSimpleBubbleModel {
327  public:
328   ContentSettingRPHBubbleModel(Delegate* delegate,
329                                content::WebContents* web_contents,
330                                ProtocolHandlerRegistry* registry);
331   ~ContentSettingRPHBubbleModel() override;
332 
333   // ContentSettingBubbleModel:
334   void CommitChanges() override;
335 
336  private:
337   void RegisterProtocolHandler();
338   void UnregisterProtocolHandler();
339   void IgnoreProtocolHandler();
340   void ClearOrSetPreviousHandler();
341   void PerformActionForSelectedItem();
342 
343   ProtocolHandlerRegistry* registry_;
344   ProtocolHandler pending_handler_;
345   ProtocolHandler previous_handler_;
346 
347   DISALLOW_COPY_AND_ASSIGN(ContentSettingRPHBubbleModel);
348 };
349 
350 // The model of the content settings bubble for media settings.
351 class ContentSettingMediaStreamBubbleModel : public ContentSettingBubbleModel {
352  public:
353   ContentSettingMediaStreamBubbleModel(Delegate* delegate,
354                                        content::WebContents* web_contents);
355 
356   ~ContentSettingMediaStreamBubbleModel() override;
357 
358   // ContentSettingBubbleModel:
359   ContentSettingMediaStreamBubbleModel* AsMediaStreamBubbleModel() override;
360   void CommitChanges() override;
361   void OnManageButtonClicked() override;
362   void OnDoneButtonClicked() override;
363 
364  private:
365   // Helper functions to check if this bubble was invoked for microphone,
366   // camera, or both devices.
367   bool MicrophoneAccessed() const;
368   bool CameraAccessed() const;
369 
370   bool MicrophoneBlocked() const;
371   bool CameraBlocked() const;
372 
373   void SetTitle();
374   void SetMessage();
375   void SetManageText();
376 
377   // Sets the data for the radio buttons of the bubble.
378   void SetRadioGroup();
379 
380   // Sets the data for the media menus of the bubble.
381   void SetMediaMenus();
382 
383   // Sets the string that suggests reloading after the settings were changed.
384   void SetCustomLink();
385 
386   // Updates the camera and microphone setting with the passed |setting|.
387   void UpdateSettings(ContentSetting setting);
388 
389 #if defined(OS_MAC)
390   // Initialize the bubble with the elements specific to the scenario when
391   // camera or mic are disabled in a system (OS) level.
392   void InitializeSystemMediaPermissionBubble();
393 #endif  // defined(OS_MAC)
394 
395   // Whether or not to show the bubble UI specific to when media permissions are
396   // turned off in a system level.
397   bool ShouldShowSystemMediaPermissions();
398 
399   // Updates the camera and microphone default device with the passed |type|
400   // and device.
401   void UpdateDefaultDeviceForType(blink::mojom::MediaStreamType type,
402                                   const std::string& device);
403 
404   // ContentSettingBubbleModel implementation.
405   void OnMediaMenuClicked(blink::mojom::MediaStreamType type,
406                           const std::string& selected_device) override;
407 
408   // The content settings that are associated with the individual radio
409   // buttons.
410   ContentSetting radio_item_setting_[2];
411   // The state of the microphone and camera access.
412   content_settings::PageSpecificContentSettings::MicrophoneCameraState state_;
413 
414   DISALLOW_COPY_AND_ASSIGN(ContentSettingMediaStreamBubbleModel);
415 };
416 
417 // The model of a bubble that acts as a quiet permission request prompt for
418 // notifications. In contrast to other bubbles (which display the current
419 // permission state after the user makes the initial decision), this is shown
420 // before the user makes the first ever permission decisions.
421 class ContentSettingNotificationsBubbleModel
422     : public ContentSettingBubbleModel {
423  public:
424   ContentSettingNotificationsBubbleModel(Delegate* delegate,
425                                          content::WebContents* web_contents);
426 
427   ~ContentSettingNotificationsBubbleModel() override;
428 
429  private:
430   void SetManageText();
431 
432   // ContentSettingBubbleModel:
433   void OnManageButtonClicked() override;
434   void OnLearnMoreClicked() override;
435   void OnDoneButtonClicked() override;
436   void OnCancelButtonClicked() override;
437   ContentSettingNotificationsBubbleModel* AsNotificationsBubbleModel() override;
438 
439   DISALLOW_COPY_AND_ASSIGN(ContentSettingNotificationsBubbleModel);
440 };
441 
442 // The model for the deceptive content bubble.
443 class ContentSettingSubresourceFilterBubbleModel
444     : public ContentSettingBubbleModel {
445  public:
446   ContentSettingSubresourceFilterBubbleModel(
447       Delegate* delegate,
448       content::WebContents* web_contents);
449 
450   ~ContentSettingSubresourceFilterBubbleModel() override;
451 
452  private:
453   void SetMessage();
454   void SetTitle();
455   void SetManageText();
456 
457   // ContentSettingBubbleModel:
458   void OnManageCheckboxChecked(bool is_checked) override;
459   ContentSettingSubresourceFilterBubbleModel* AsSubresourceFilterBubbleModel()
460       override;
461   void OnLearnMoreClicked() override;
462   void CommitChanges() override;
463 
464   bool is_checked_ = false;
465 
466   DISALLOW_COPY_AND_ASSIGN(ContentSettingSubresourceFilterBubbleModel);
467 };
468 
469 // The model for automatic downloads setting.
470 class ContentSettingDownloadsBubbleModel : public ContentSettingBubbleModel {
471  public:
472   ContentSettingDownloadsBubbleModel(Delegate* delegate,
473                                      content::WebContents* web_contents);
474   ~ContentSettingDownloadsBubbleModel() override;
475 
476   // ContentSettingBubbleModel overrides:
477   ContentSettingDownloadsBubbleModel* AsDownloadsBubbleModel() override;
478   void CommitChanges() override;
479 
480  private:
481   void SetRadioGroup();
482   void SetTitle();
483   void SetManageText();
484 
485   // ContentSettingBubbleModel overrides:
486   void OnManageButtonClicked() override;
487 
488   DISALLOW_COPY_AND_ASSIGN(ContentSettingDownloadsBubbleModel);
489 };
490 
491 class ContentSettingSingleRadioGroup : public ContentSettingSimpleBubbleModel {
492  public:
493   ContentSettingSingleRadioGroup(Delegate* delegate,
494                                  content::WebContents* web_contents,
495                                  ContentSettingsType content_type);
496   ~ContentSettingSingleRadioGroup() override;
497 
498   // ContentSettingSimpleBubbleModel:
499   void CommitChanges() override;
500 
501  protected:
502   bool settings_changed() const;
503 
504  private:
505   FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest, AllowRadioButtonSelected);
506   FRIEND_TEST_ALL_PREFIXES(FramebustBlockBrowserTest,
507                            DisallowRadioButtonSelected);
508 
509   void SetRadioGroup();
510   void SetNarrowestContentSetting(ContentSetting setting);
511 
512   ContentSetting block_setting_;
513 
514   DISALLOW_COPY_AND_ASSIGN(ContentSettingSingleRadioGroup);
515 };
516 
517 // The bubble that informs users that Chrome does not have access to Location
518 // and guides them to the system preferences to fix that problem if they wish.
519 class ContentSettingGeolocationBubbleModel
520     : public ContentSettingSingleRadioGroup {
521  public:
522   ContentSettingGeolocationBubbleModel(Delegate* delegate,
523                                        content::WebContents* web_contents);
524 
525   ContentSettingGeolocationBubbleModel(
526       const ContentSettingGeolocationBubbleModel&) = delete;
527   ContentSettingGeolocationBubbleModel& operator=(
528       const ContentSettingGeolocationBubbleModel&) = delete;
529 
530   ~ContentSettingGeolocationBubbleModel() override;
531 
532   // ContentSettingBubbleModel:
533   void OnManageButtonClicked() override;
534   void OnDoneButtonClicked() override;
535   void CommitChanges() override;
536 
537  private:
538   // Initialize the bubble with the elements specific to the scenario when
539   // geolocation is disabled on the system (OS) level.
540   void InitializeSystemGeolocationPermissionBubble();
541   void SetCustomLink();
542 
543   // Whether or not we are showing the bubble UI specific to when geolocation
544   // permissions are turned off on a system level.
545   bool show_system_geolocation_bubble_ = false;
546 };
547 
548 #if !defined(OS_ANDROID)
549 // The model for the blocked Framebust bubble.
550 class ContentSettingFramebustBlockBubbleModel
551     : public ContentSettingSingleRadioGroup,
552       public blocked_content::UrlListManager::Observer {
553  public:
554   ContentSettingFramebustBlockBubbleModel(Delegate* delegate,
555                                           content::WebContents* web_contents);
556 
557   ~ContentSettingFramebustBlockBubbleModel() override;
558 
559   // ContentSettingBubbleModel:
560   void OnListItemClicked(int index, const ui::Event& event) override;
561   ContentSettingFramebustBlockBubbleModel* AsFramebustBlockBubbleModel()
562       override;
563 
564   // UrlListManager::Observer:
565   void BlockedUrlAdded(int32_t id, const GURL& blocked_url) override;
566 
567  private:
568   ListItem CreateListItem(const GURL& url);
569 
570   ScopedObserver<blocked_content::UrlListManager,
571                  blocked_content::UrlListManager::Observer>
572       url_list_observer_;
573 
574   DISALLOW_COPY_AND_ASSIGN(ContentSettingFramebustBlockBubbleModel);
575 };
576 #endif  // !defined(OS_ANDROID)
577 
578 #endif  // CHROME_BROWSER_UI_CONTENT_SETTINGS_CONTENT_SETTING_BUBBLE_MODEL_H_
579