blob: d622decb3e21b10e9f09a80ca9fd267b2c800743 [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.
#ifndef CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_
#define CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_
#include "base/time/default_clock.h"
#include "components/permissions/permission_request_manager.h"
#include "components/safe_browsing/content/browser/ui_manager.h"
#include "components/security_interstitials/core/unsafe_resource.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents_observer.h"
namespace blink {
class WebMouseEvent;
}
namespace safe_browsing {
// Used for UMA. There may be more than one event per navigation (e.g.
// kAll and kWarningShownOnKeypress).
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class DelayedWarningEvent {
// User loaded a page with a delayed warning.
kPageLoaded = 0,
// User left the page and the warning was never shown.
kWarningNotShown = 1,
// User pressed a key and the warning was shown.
kWarningShownOnKeypress = 2,
// User clicked on the page at least once but the feature isn't configured to
// show warnings on mouse clicks.
kWarningNotTriggeredOnMouseClick = 3,
// User clicked on the page and the warning was shown.
kWarningShownOnMouseClick = 4,
// The page tried to enter fullscreen mode.
kWarningShownOnFullscreenAttempt = 5,
// The page tried to initiate a download and we cancelled it. This doesn't
// show an interstitial.
kDownloadCancelled = 6,
// The page triggered a permission request. It was denied and the warning was
// shown.
kWarningShownOnPermissionRequest = 7,
// The page tried to display a JavaScript dialog (alert/confirm/prompt). It
// was blocked and the warning was shown.
kWarningShownOnJavaScriptDialog = 8,
// The page was denied a password save or autofill request. This doesn't show
// an interstitial and is recorded once per navigation.
kPasswordSaveOrAutofillDenied = 9,
// The page triggered a desktop capture request ("example.com wants to share
// the contents of the screen"). It was denied and the warning was shown.
kWarningShownOnDesktopCaptureRequest = 10,
// User pasted something on the page and the warning was shown.
kWarningShownOnPaste = 11,
kMaxValue = kWarningShownOnPaste,
};
// Name of the recorded histograms when the user did not disable URL elision via
// "Always Show Full URLs" menu option or by installing Suspicious Site Reporter
// extension.
extern const char kDelayedWarningsHistogram[];
extern const char kDelayedWarningsTimeOnPageHistogram[];
// Same as above but only recorded if the user disabled URL elision.
extern const char kDelayedWarningsWithElisionDisabledHistogram[];
extern const char kDelayedWarningsTimeOnPageWithElisionDisabledHistogram[];
// Observes user interactions and shows an interstitial if necessary.
// Only created when an interstitial was about to be displayed but was delayed
// due to the Delayed Warnings experiment. Deleted once the interstitial is
// shown, or the tab is closed or navigated away.
class SafeBrowsingUserInteractionObserver
: public base::SupportsUserData::Data,
public content::WebContentsObserver,
public permissions::PermissionRequestManager::Observer {
public:
// Creates an observer for given |web_contents|. |resource| is the unsafe
// resource for which a delayed interstitial will be displayed.
// |is_main_frame| is true if the interstitial is for the top frame. If false,
// it's for a subresource / subframe.
// |ui_manager| is the UIManager that shows the actual warning.
static void CreateForWebContents(
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
bool is_main_frame,
scoped_refptr<SafeBrowsingUIManager> ui_manager);
static SafeBrowsingUserInteractionObserver* FromWebContents(
content::WebContents* web_contents);
// See CreateForWebContents() for parameters. These need to be public.
SafeBrowsingUserInteractionObserver(
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
bool is_main_frame,
scoped_refptr<SafeBrowsingUIManager> ui_manager);
~SafeBrowsingUserInteractionObserver() override;
// content::WebContentsObserver methods:
void RenderFrameHostChanged(content::RenderFrameHost* old_frame,
content::RenderFrameHost* new_frame) override;
void WebContentsDestroyed() override;
void DidFinishNavigation(content::NavigationHandle* handle) override;
void DidToggleFullscreenModeForTab(bool entered_fullscreen,
bool will_cause_resize) override;
void OnPaste() override;
// permissions::PermissionRequestManager::Observer methods:
void OnBubbleAdded() override;
// Called by the JavaScript dialog manager when the current page is about to
// show a JavaScript dialog (alert, confirm or prompt). Shows the
// delayed interstitial immediately.
void OnJavaScriptDialog();
// Called when a password save or autofill request is denied to the current
// page. Records a metric once per navigation.
void OnPasswordSaveOrAutofillDenied();
// Called by the desktop capture access handler when the current page requests
// a desktop capture. Shows the delayed interstitial immediately.
void OnDesktopCaptureRequest();
static void SetSuspiciousSiteReporterExtensionIdForTesting(
const char* extension_id);
static void ResetSuspiciousSiteReporterExtensionIdForTesting();
void SetClockForTesting(base::Clock* clock);
base::Time GetCreationTimeForTesting() const;
private:
void RecordUMA(DelayedWarningEvent event);
bool HandleKeyPress(const content::NativeWebKeyboardEvent& event);
bool HandleMouseEvent(const blink::WebMouseEvent& event);
void ShowInterstitial(DelayedWarningEvent event);
void CleanUp();
void Detach();
content::RenderWidgetHost::KeyPressEventCallback key_press_callback_;
content::RenderWidgetHost::MouseEventCallback mouse_event_callback_;
content::WebContents* web_contents_;
security_interstitials::UnsafeResource resource_;
scoped_refptr<SafeBrowsingUIManager> ui_manager_;
bool interstitial_shown_ = false;
bool mouse_click_with_no_warning_recorded_ = false;
bool password_save_or_autofill_denied_metric_recorded_ = false;
// This will be set to true if the initial navigation that caused this
// observer to be created has finished. We need this extra bit because
// observers can only detect download navigations in DidFinishNavigation.
// However, this hook is also called for the initial navigation, so we ignore
// it the first time the hook is called.
bool initial_navigation_finished_ = false;
// Id of the Suspicious Site Reporter extension. Only set in tests.
static const char* suspicious_site_reporter_extension_id_;
// The time that this observer was created. Used for recording histograms.
base::Time creation_time_;
// This clock is used to record the delta from |creation_time_| when the
// observer is detached, and can be injected by tests.
base::Clock* clock_;
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_USER_INTERACTION_OBSERVER_H_