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// Classes for managing the SafeBrowsing interstitial pages.
6//
7// When a user is about to visit a page the SafeBrowsing system has deemed to
8// be malicious, either as malware or a phishing page, we show an interstitial
9// page with some options (go back, continue) to give the user a chance to avoid
10// the harmful page.
11//
12// The SafeBrowsingBlockingPage is created by the SafeBrowsingUIManager on the
13// UI thread when we've determined that a page is malicious. The operation of
14// the blocking page occurs on the UI thread, where it waits for the user to
15// make a decision about what to do: either go back or continue on.
16//
17// The blocking page forwards the result of the user's choice back to the
18// SafeBrowsingUIManager so that we can cancel the request for the new page,
19// or allow it to continue.
20//
21// A web page may contain several resources flagged as malware/phishing.  This
22// results into more than one interstitial being shown.  On the first unsafe
23// resource received we show an interstitial.  Any subsequent unsafe resource
24// notifications while the first interstitial is showing is queued.  If the user
25// decides to proceed in the first interstitial, we display all queued unsafe
26// resources in a new interstitial.
27
28#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
29#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
30
31#include <map>
32#include <string>
33#include <vector>
34
35#include "base/gtest_prod_util.h"
36#include "base/time/time.h"
37#include "chrome/browser/safe_browsing/ui_manager.h"
38#include "content/public/browser/interstitial_page_delegate.h"
39#include "url/gurl.h"
40
41class MalwareDetails;
42class SafeBrowsingBlockingPageFactory;
43
44namespace base {
45class DictionaryValue;
46class MessageLoop;
47}
48
49namespace content {
50class InterstitialPage;
51class WebContents;
52}
53
54class SafeBrowsingBlockingPage : public content::InterstitialPageDelegate {
55 public:
56  typedef SafeBrowsingUIManager::UnsafeResource UnsafeResource;
57  typedef std::vector<UnsafeResource> UnsafeResourceList;
58  typedef std::map<content::WebContents*, UnsafeResourceList> UnsafeResourceMap;
59
60  virtual ~SafeBrowsingBlockingPage();
61
62  // Shows a blocking page warning the user about phishing/malware for a
63  // specific resource.
64  // You can call this method several times, if an interstitial is already
65  // showing, the new one will be queued and displayed if the user decides
66  // to proceed on the currently showing interstitial.
67  static void ShowBlockingPage(
68      SafeBrowsingUIManager* ui_manager, const UnsafeResource& resource);
69
70  // Makes the passed |factory| the factory used to instanciate
71  // SafeBrowsingBlockingPage objects. Useful for tests.
72  static void RegisterFactory(SafeBrowsingBlockingPageFactory* factory) {
73    factory_ = factory;
74  }
75
76  // InterstitialPageDelegate method:
77  virtual void CommandReceived(const std::string& command) OVERRIDE;
78  virtual void OverrideRendererPrefs(
79      content::RendererPreferences* prefs) OVERRIDE;
80  virtual void OnProceed() OVERRIDE;
81  virtual void OnDontProceed() OVERRIDE;
82
83 protected:
84  friend class SafeBrowsingBlockingPageTest;
85  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageTest,
86                           ProceedThenDontProceed);
87  friend class SafeBrowsingBlockingPageV2Test;
88  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageV2Test,
89                           ProceedThenDontProceed);
90
91  void SetReportingPreference(bool report);
92
93  // Don't instanciate this class directly, use ShowBlockingPage instead.
94  SafeBrowsingBlockingPage(SafeBrowsingUIManager* ui_manager,
95                           content::WebContents* web_contents,
96                           const UnsafeResourceList& unsafe_resources);
97
98  // After a malware interstitial where the user opted-in to the
99  // report but clicked "proceed anyway", we delay the call to
100  // MalwareDetails::FinishCollection() by this much time (in
101  // milliseconds), in order to get data from the blocked resource itself.
102  int64 malware_details_proceed_delay_ms_;
103  content::InterstitialPage* interstitial_page() const {
104    return interstitial_page_;
105  }
106
107  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageTest, MalwareReports);
108  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingBlockingPageV2Test, MalwareReports);
109
110  enum BlockingPageEvent {
111    SHOW,
112    PROCEED,
113    DONT_PROCEED,
114    SHOW_ADVANCED,
115  };
116
117  // Records a user action for this interstitial, using the form
118  // SBInterstitial[Phishing|Malware|Multiple][Show|Proceed|DontProceed].
119  void RecordUserAction(BlockingPageEvent event);
120
121  // Records the time it took for the user to react to the
122  // interstitial.  We won't double-count if this method is called
123  // multiple times.
124  void RecordUserReactionTime(const std::string& command);
125
126  // Checks if we should even show the malware details option. For example, we
127  // don't show it in incognito mode.
128  bool CanShowMalwareDetailsOption();
129
130  // Called when the insterstitial is going away. If there is a
131  // pending malware details object, we look at the user's
132  // preferences, and if the option to send malware details is
133  // enabled, the report is scheduled to be sent on the |ui_manager_|.
134  void FinishMalwareDetails(int64 delay_ms);
135
136  // Returns the boolean value of the given |pref| from the PrefService of the
137  // Profile associated with |web_contents_|.
138  bool IsPrefEnabled(const char* pref);
139
140  // A list of SafeBrowsingUIManager::UnsafeResource for a tab that the user
141  // should be warned about.  They are queued when displaying more than one
142  // interstitial at a time.
143  static UnsafeResourceMap* GetUnsafeResourcesMap();
144
145  // Notifies the SafeBrowsingUIManager on the IO thread whether to proceed
146  // or not for the |resources|.
147  static void NotifySafeBrowsingUIManager(
148      SafeBrowsingUIManager* ui_manager,
149      const UnsafeResourceList& resources, bool proceed);
150
151  // Returns true if the passed |unsafe_resources| is blocking the load of
152  // the main page.
153  static bool IsMainPageLoadBlocked(
154      const UnsafeResourceList& unsafe_resources);
155
156  friend class SafeBrowsingBlockingPageFactoryImpl;
157
158  // For reporting back user actions.
159  SafeBrowsingUIManager* ui_manager_;
160  base::MessageLoop* report_loop_;
161
162  // True if the interstitial is blocking the main page because it is on one
163  // of our lists.  False if a subresource is being blocked, or in the case of
164  // client-side detection where the interstitial is shown after page load
165  // finishes.
166  bool is_main_frame_load_blocked_;
167
168  // The index of a navigation entry that should be removed when DontProceed()
169  // is invoked, -1 if not entry should be removed.
170  int navigation_entry_index_to_remove_;
171
172  // The list of unsafe resources this page is warning about.
173  UnsafeResourceList unsafe_resources_;
174
175  // A MalwareDetails object that we start generating when the
176  // blocking page is shown. The object will be sent when the warning
177  // is gone (if the user enables the feature).
178  scoped_refptr<MalwareDetails> malware_details_;
179
180  bool proceeded_;
181
182  content::WebContents* web_contents_;
183  GURL url_;
184  content::InterstitialPage* interstitial_page_;  // Owns us
185
186  // Time when the interstitial was show.  This variable is set in
187  // GetHTMLContents() which is called right before the interstitial
188  // is shown to the user. Will return is_null() once we reported the
189  // user action.
190  base::TimeTicks interstitial_show_time_;
191
192  // Whether the user has expanded the "see more" section of the page already
193  // during this interstitial page.
194  bool has_expanded_see_more_section_;
195
196  // Which type of interstitial this is.
197  enum {
198    TYPE_MALWARE,
199    TYPE_PHISHING,
200    TYPE_MALWARE_AND_PHISHING,
201  } interstitial_type_;
202
203  // The factory used to instanciate SafeBrowsingBlockingPage objects.
204  // Usefull for tests, so they can provide their own implementation of
205  // SafeBrowsingBlockingPage.
206  static SafeBrowsingBlockingPageFactory* factory_;
207
208  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
209};
210
211class SafeBrowsingBlockingPageV1 : public SafeBrowsingBlockingPage {
212 public:
213  // Don't instanciate this class directly, use ShowBlockingPage instead.
214  SafeBrowsingBlockingPageV1(SafeBrowsingUIManager* ui_manager,
215                             content::WebContents* web_contents,
216                             const UnsafeResourceList& unsafe_resources);
217
218  // InterstitialPageDelegate method:
219  virtual std::string GetHTMLContents() OVERRIDE;
220
221 private:
222  // Fills the passed dictionary with the strings passed to JS Template when
223  // creating the HTML.
224  void PopulateMultipleThreatStringDictionary(base::DictionaryValue* strings);
225  void PopulateMalwareStringDictionary(base::DictionaryValue* strings);
226  void PopulatePhishingStringDictionary(base::DictionaryValue* strings);
227
228  // A helper method used by the Populate methods above used to populate common
229  // fields.
230  void PopulateStringDictionary(base::DictionaryValue* strings,
231                                const string16& title,
232                                const string16& headline,
233                                const string16& description1,
234                                const string16& description2,
235                                const string16& description3);
236
237  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageV1);
238};
239
240class SafeBrowsingBlockingPageV2 : public SafeBrowsingBlockingPage {
241 public:
242  // Don't instanciate this class directly, use ShowBlockingPage instead.
243  SafeBrowsingBlockingPageV2(SafeBrowsingUIManager* ui_manager,
244                             content::WebContents* web_contents,
245                             const UnsafeResourceList& unsafe_resources);
246
247  // InterstitialPageDelegate method:
248  virtual std::string GetHTMLContents() OVERRIDE;
249
250 private:
251  // Fills the passed dictionary with the strings passed to JS Template when
252  // creating the HTML.
253  void PopulateMultipleThreatStringDictionary(base::DictionaryValue* strings);
254  void PopulateMalwareStringDictionary(base::DictionaryValue* strings);
255  void PopulatePhishingStringDictionary(base::DictionaryValue* strings);
256
257  // A helper method used by the Populate methods above used to populate common
258  // fields.
259  void PopulateStringDictionary(base::DictionaryValue* strings,
260                                const string16& title,
261                                const string16& headline,
262                                const string16& description1,
263                                const string16& description2,
264                                const string16& description3);
265
266  // For the FieldTrial: this contains the name of the condition.
267  std::string trialCondition_;
268
269  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageV2);
270};
271
272// Factory for creating SafeBrowsingBlockingPage.  Useful for tests.
273class SafeBrowsingBlockingPageFactory {
274 public:
275  virtual ~SafeBrowsingBlockingPageFactory() { }
276
277  virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
278      SafeBrowsingUIManager* ui_manager,
279      content::WebContents* web_contents,
280      const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) = 0;
281};
282
283#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
284