blob: 249349f5b5c331b12030c2edf47bb6f3463ceb98 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/user_interaction_observer.h"
#include <string>
#include "components/safe_browsing/core/features.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
namespace {
const char kWebContentsUserDataKey[] =
"web_contents_safe_browsing_user_interaction_observer";
}
namespace safe_browsing {
SafeBrowsingUserInteractionObserver::SafeBrowsingUserInteractionObserver(
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
bool is_main_frame,
scoped_refptr<SafeBrowsingUIManager> ui_manager)
: content::WebContentsObserver(web_contents),
web_contents_(web_contents),
resource_(resource),
ui_manager_(ui_manager) {
DCHECK(base::FeatureList::IsEnabled(kDelayedWarnings));
key_press_callback_ =
base::BindRepeating(&SafeBrowsingUserInteractionObserver::HandleKeyPress,
base::Unretained(this));
// Pass a callback to the render widget host instead of implementing
// WebContentsObserver::DidGetUserInteraction(). The reason for this is that
// render widget host handles keyboard events earlier and the callback can
// indicate that it wants the key press to be ignored.
// (DidGetUserInteraction() can only observe and not cancel the event.)
web_contents->GetRenderViewHost()->GetWidget()->AddKeyPressEventCallback(
key_press_callback_);
}
SafeBrowsingUserInteractionObserver::~SafeBrowsingUserInteractionObserver() {
web_contents_->GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback(
key_press_callback_);
}
// static
void SafeBrowsingUserInteractionObserver::CreateForWebContents(
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
bool is_main_frame,
scoped_refptr<SafeBrowsingUIManager> ui_manager) {
DCHECK(!FromWebContents(web_contents));
auto observer = std::make_unique<SafeBrowsingUserInteractionObserver>(
web_contents, resource, is_main_frame, ui_manager);
web_contents->SetUserData(kWebContentsUserDataKey, std::move(observer));
}
// static
SafeBrowsingUserInteractionObserver*
SafeBrowsingUserInteractionObserver::FromWebContents(
content::WebContents* web_contents) {
return static_cast<SafeBrowsingUserInteractionObserver*>(
web_contents->GetUserData(kWebContentsUserDataKey));
}
void SafeBrowsingUserInteractionObserver::RenderViewHostChanged(
content::RenderViewHost* old_host,
content::RenderViewHost* new_host) {
old_host->GetWidget()->RemoveKeyPressEventCallback(key_press_callback_);
new_host->GetWidget()->AddKeyPressEventCallback(key_press_callback_);
}
void SafeBrowsingUserInteractionObserver::WebContentsDestroyed() {
CleanUp();
}
void SafeBrowsingUserInteractionObserver::DidStartNavigation(
content::NavigationHandle* handle) {
// Ignore subframe navigations and same document navigations. These don't
// show full page interstitials.
if (!handle->IsInMainFrame() || handle->IsSameDocument()) {
return;
}
web_contents()->RemoveUserData(kWebContentsUserDataKey);
}
bool SafeBrowsingUserInteractionObserver::HandleKeyPress(
const content::NativeWebKeyboardEvent& event) {
CleanUp();
// Show the interstitial.
SafeBrowsingUIManager::StartDisplayingBlockingPage(ui_manager_, resource_);
// DO NOT add code past this point. |this| is destroyed.
return true;
}
void SafeBrowsingUserInteractionObserver::CleanUp() {
web_contents_->GetRenderViewHost()->GetWidget()->RemoveKeyPressEventCallback(
key_press_callback_);
}
} // namespace safe_browsing