Home | History | Annotate | Download | only in supervised_user
      1 // Copyright 2014 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 "chrome/browser/supervised_user/supervised_user_navigation_observer.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback.h"
      9 #include "base/metrics/histogram.h"
     10 #include "base/strings/string_util.h"
     11 #include "chrome/browser/history/history_service.h"
     12 #include "chrome/browser/history/history_service_factory.h"
     13 #include "chrome/browser/history/history_types.h"
     14 #include "chrome/browser/infobars/infobar_service.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/supervised_user/supervised_user_interstitial.h"
     17 #include "chrome/browser/supervised_user/supervised_user_resource_throttle.h"
     18 #include "chrome/browser/supervised_user/supervised_user_service.h"
     19 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
     20 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
     21 #include "chrome/browser/tab_contents/tab_util.h"
     22 #include "components/infobars/core/confirm_infobar_delegate.h"
     23 #include "components/infobars/core/infobar.h"
     24 #include "content/public/browser/browser_thread.h"
     25 #include "content/public/browser/navigation_entry.h"
     26 #include "content/public/browser/render_process_host.h"
     27 #include "content/public/browser/render_view_host.h"
     28 #include "content/public/browser/user_metrics.h"
     29 #include "grit/generated_resources.h"
     30 #include "ui/base/l10n/l10n_util.h"
     31 
     32 #if !defined(OS_ANDROID)
     33 #include "chrome/browser/ui/browser.h"
     34 #include "chrome/browser/ui/browser_commands.h"
     35 #include "chrome/browser/ui/browser_finder.h"
     36 #include "chrome/browser/ui/browser_list.h"
     37 #include "chrome/browser/ui/host_desktop.h"
     38 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     39 #endif
     40 
     41 using base::Time;
     42 using content::NavigationEntry;
     43 
     44 namespace {
     45 
     46 
     47 // Helpers --------------------------------------------------------------------
     48 
     49 #if !defined(OS_ANDROID)
     50 // TODO(bauerb): Get rid of the platform-specific #ifdef here.
     51 // http://crbug.com/313377
     52 void GoBackToSafety(content::WebContents* web_contents) {
     53   // For now, just go back one page (the user didn't retreat from that page,
     54   // so it should be okay).
     55   content::NavigationController* controller =
     56       &web_contents->GetController();
     57   if (controller->CanGoBack()) {
     58     controller->GoBack();
     59     return;
     60   }
     61 
     62   // If we can't go back (because we opened a new tab), try to close the tab.
     63   // If this is the last tab on this desktop, open a new window.
     64   chrome::HostDesktopType host_desktop_type =
     65       chrome::GetHostDesktopTypeForNativeView(web_contents->GetNativeView());
     66   const BrowserList* browser_list = BrowserList::GetInstance(host_desktop_type);
     67   if (browser_list->size() == 1) {
     68     Browser* browser = browser_list->get(0);
     69     DCHECK(browser == chrome::FindBrowserWithWebContents(web_contents));
     70     if (browser->tab_strip_model()->count() == 1)
     71       chrome::NewEmptyWindow(browser->profile(), browser->host_desktop_type());
     72   }
     73 
     74   web_contents->GetDelegate()->CloseContents(web_contents);
     75 }
     76 #endif
     77 
     78 // SupervisedUserWarningInfoBarDelegate ---------------------------------------
     79 
     80 class SupervisedUserWarningInfoBarDelegate : public ConfirmInfoBarDelegate {
     81  public:
     82   // Creates a supervised user warning infobar and delegate and adds the infobar
     83   // to |infobar_service|.  Returns the infobar if it was successfully added.
     84   static infobars::InfoBar* Create(InfoBarService* infobar_service);
     85 
     86  private:
     87   SupervisedUserWarningInfoBarDelegate();
     88   virtual ~SupervisedUserWarningInfoBarDelegate();
     89 
     90   // ConfirmInfoBarDelegate:
     91   virtual bool ShouldExpire(const NavigationDetails& details) const OVERRIDE;
     92   virtual void InfoBarDismissed() OVERRIDE;
     93   virtual base::string16 GetMessageText() const OVERRIDE;
     94   virtual int GetButtons() const OVERRIDE;
     95   virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
     96   virtual bool Accept() OVERRIDE;
     97 
     98   DISALLOW_COPY_AND_ASSIGN(SupervisedUserWarningInfoBarDelegate);
     99 };
    100 
    101 // static
    102 infobars::InfoBar* SupervisedUserWarningInfoBarDelegate::Create(
    103     InfoBarService* infobar_service) {
    104   return infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
    105       scoped_ptr<ConfirmInfoBarDelegate>(
    106           new SupervisedUserWarningInfoBarDelegate())));
    107 }
    108 
    109 SupervisedUserWarningInfoBarDelegate::SupervisedUserWarningInfoBarDelegate()
    110     : ConfirmInfoBarDelegate() {
    111 }
    112 
    113 SupervisedUserWarningInfoBarDelegate::~SupervisedUserWarningInfoBarDelegate() {
    114 }
    115 
    116 bool SupervisedUserWarningInfoBarDelegate::ShouldExpire(
    117     const NavigationDetails& details) const {
    118   // SupervisedUserNavigationObserver removes us below.
    119   return false;
    120 }
    121 
    122 void SupervisedUserWarningInfoBarDelegate::InfoBarDismissed() {
    123   content::WebContents* web_contents =
    124       InfoBarService::WebContentsFromInfoBar(infobar());
    125   SupervisedUserNavigationObserver::FromWebContents(
    126       web_contents)->WarnInfoBarDismissed();
    127 }
    128 
    129 base::string16 SupervisedUserWarningInfoBarDelegate::GetMessageText() const {
    130   return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_MESSAGE);
    131 }
    132 
    133 int SupervisedUserWarningInfoBarDelegate::GetButtons() const {
    134   return BUTTON_OK;
    135 }
    136 
    137 base::string16 SupervisedUserWarningInfoBarDelegate::GetButtonLabel(
    138     InfoBarButton button) const {
    139   DCHECK_EQ(BUTTON_OK, button);
    140   return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_GO_BACK);
    141 }
    142 
    143 bool SupervisedUserWarningInfoBarDelegate::Accept() {
    144 #if defined(OS_ANDROID)
    145   // TODO(bauerb): Get rid of the platform-specific #ifdef here.
    146   // http://crbug.com/313377
    147   NOTIMPLEMENTED();
    148 #else
    149   GoBackToSafety(InfoBarService::WebContentsFromInfoBar(infobar()));
    150 #endif
    151 
    152   return false;
    153 }
    154 
    155 
    156 }  // namespace
    157 
    158 // SupervisedUserNavigationObserver -------------------------------------------
    159 
    160 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SupervisedUserNavigationObserver);
    161 
    162 SupervisedUserNavigationObserver::~SupervisedUserNavigationObserver() {
    163 }
    164 
    165 SupervisedUserNavigationObserver::SupervisedUserNavigationObserver(
    166     content::WebContents* web_contents)
    167     : WebContentsObserver(web_contents),
    168       warn_infobar_(NULL) {
    169   Profile* profile =
    170       Profile::FromBrowserContext(web_contents->GetBrowserContext());
    171   supervised_user_service_ =
    172       SupervisedUserServiceFactory::GetForProfile(profile);
    173   url_filter_ = supervised_user_service_->GetURLFilterForUIThread();
    174 }
    175 
    176 void SupervisedUserNavigationObserver::WarnInfoBarDismissed() {
    177   DCHECK(warn_infobar_);
    178   warn_infobar_ = NULL;
    179 }
    180 
    181 void SupervisedUserNavigationObserver::ProvisionalChangeToMainFrameUrl(
    182     const GURL& url,
    183     content::RenderFrameHost* render_frame_host) {
    184   SupervisedUserURLFilter::FilteringBehavior behavior =
    185       url_filter_->GetFilteringBehaviorForURL(url);
    186 
    187   if (behavior == SupervisedUserURLFilter::WARN || !warn_infobar_)
    188     return;
    189 
    190   // If we shouldn't have a warn infobar remove it here.
    191   InfoBarService::FromWebContents(web_contents())->RemoveInfoBar(warn_infobar_);
    192   warn_infobar_ = NULL;
    193 }
    194 
    195 void SupervisedUserNavigationObserver::DidCommitProvisionalLoadForFrame(
    196     int64 frame_id,
    197     const base::string16& frame_unique_name,
    198     bool is_main_frame,
    199     const GURL& url,
    200     content::PageTransition transition_type,
    201     content::RenderViewHost* render_view_host) {
    202   if (!is_main_frame)
    203     return;
    204 
    205   DVLOG(1) << "DidCommitProvisionalLoadForFrame " << url.spec();
    206   SupervisedUserURLFilter::FilteringBehavior behavior =
    207       url_filter_->GetFilteringBehaviorForURL(url);
    208 
    209   if (behavior == SupervisedUserURLFilter::WARN && !warn_infobar_) {
    210     warn_infobar_ = SupervisedUserWarningInfoBarDelegate::Create(
    211         InfoBarService::FromWebContents(web_contents()));
    212   }
    213 }
    214 
    215 // static
    216 void SupervisedUserNavigationObserver::OnRequestBlocked(
    217     int render_process_host_id,
    218     int render_view_id,
    219     const GURL& url,
    220     const base::Callback<void(bool)>& callback) {
    221   content::WebContents* web_contents =
    222       tab_util::GetWebContentsByID(render_process_host_id, render_view_id);
    223   if (!web_contents) {
    224     content::BrowserThread::PostTask(
    225         content::BrowserThread::IO, FROM_HERE, base::Bind(callback, false));
    226     return;
    227   }
    228 
    229   SupervisedUserNavigationObserver* navigation_observer =
    230       SupervisedUserNavigationObserver::FromWebContents(web_contents);
    231   if (navigation_observer)
    232     navigation_observer->OnRequestBlockedInternal(url);
    233 
    234   // Show the interstitial.
    235   SupervisedUserInterstitial::Show(web_contents, url, callback);
    236 }
    237 
    238 void SupervisedUserNavigationObserver::OnRequestBlockedInternal(
    239     const GURL& url) {
    240   Time timestamp = Time::Now();  // TODO(bauerb): Use SaneTime when available.
    241   // Create a history entry for the attempt and mark it as such.
    242   history::HistoryAddPageArgs add_page_args(
    243         url, timestamp, web_contents(), 0,
    244         url, history::RedirectList(),
    245         content::PAGE_TRANSITION_BLOCKED, history::SOURCE_BROWSED,
    246         false);
    247 
    248   // Add the entry to the history database.
    249   Profile* profile =
    250       Profile::FromBrowserContext(web_contents()->GetBrowserContext());
    251   HistoryService* history_service =
    252      HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
    253 
    254   // |history_service| is null if saving history is disabled.
    255   if (history_service)
    256     history_service->AddPage(add_page_args);
    257 
    258   scoped_ptr<NavigationEntry> entry(NavigationEntry::Create());
    259   entry->SetVirtualURL(url);
    260   entry->SetTimestamp(timestamp);
    261   blocked_navigations_.push_back(entry.release());
    262   SupervisedUserService* supervised_user_service =
    263       SupervisedUserServiceFactory::GetForProfile(profile);
    264   supervised_user_service->DidBlockNavigation(web_contents());
    265 }
    266