Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 1 | // Copyright 2019 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 | |
Emily Stark | 474b8ca | 2019-10-24 15:35:39 | [diff] [blame] | 5 | #include "chrome/browser/reputation/reputation_web_contents_observer.h" |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 6 | |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 7 | #include <string> |
Aidan Beggs | dead92c | 2019-10-08 21:37:27 | [diff] [blame] | 8 | #include <utility> |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 9 | |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 10 | #include "base/metrics/histogram_functions.h" |
Livvie Lin | d2539b4 | 2019-09-04 18:37:55 | [diff] [blame] | 11 | #include "base/metrics/histogram_macros.h" |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 12 | #include "build/build_config.h" |
| 13 | #include "chrome/browser/profiles/profile.h" |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 14 | #include "chrome/browser/reputation/reputation_service.h" |
Joe DeBlasio | 92c3003 | 2019-10-11 16:48:07 | [diff] [blame] | 15 | #include "components/security_state/core/features.h" |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 16 | #include "content/public/browser/navigation_entry.h" |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 17 | |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 18 | namespace { |
| 19 | |
| 20 | void OnSafetyTipClosed(security_state::SafetyTipStatus safety_tip_status, |
| 21 | base::Time start_time, |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 22 | SafetyTipInteraction action) { |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 23 | std::string action_suffix; |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 24 | bool warning_dismissed = false; |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 25 | switch (action) { |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 26 | case SafetyTipInteraction::kNoAction: |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 27 | action_suffix = "NoAction"; |
| 28 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 29 | case SafetyTipInteraction::kLeaveSite: |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 30 | action_suffix = "LeaveSite"; |
| 31 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 32 | case SafetyTipInteraction::kDismiss: |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 33 | NOTREACHED(); |
| 34 | // Do nothing because the dismissal action passed to this method should |
| 35 | // be the more specific version (esc, close, or ignore). |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 36 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 37 | case SafetyTipInteraction::kDismissWithEsc: |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 38 | action_suffix = "DismissWithEsc"; |
| 39 | warning_dismissed = true; |
| 40 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 41 | case SafetyTipInteraction::kDismissWithClose: |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 42 | action_suffix = "DismissWithClose"; |
| 43 | warning_dismissed = true; |
| 44 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 45 | case SafetyTipInteraction::kDismissWithIgnore: |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 46 | action_suffix = "DismissWithIgnore"; |
| 47 | warning_dismissed = true; |
| 48 | break; |
Emily Stark | 53b2989 | 2019-10-24 16:30:41 | [diff] [blame] | 49 | case SafetyTipInteraction::kLearnMore: |
Joe DeBlasio | 29a2ab2 | 2019-10-04 23:47:10 | [diff] [blame] | 50 | action_suffix = "LearnMore"; |
| 51 | break; |
Livvie Lin | 753db88c | 2019-09-26 21:16:50 | [diff] [blame] | 52 | } |
| 53 | if (warning_dismissed) { |
| 54 | base::UmaHistogramCustomTimes( |
| 55 | security_state::GetSafetyTipHistogramName( |
| 56 | std::string("Security.SafetyTips.OpenTime.Dismiss"), |
| 57 | safety_tip_status), |
| 58 | base::Time::Now() - start_time, base::TimeDelta::FromMilliseconds(1), |
| 59 | base::TimeDelta::FromHours(1), 100); |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 60 | } |
| 61 | base::UmaHistogramCustomTimes( |
| 62 | security_state::GetSafetyTipHistogramName( |
| 63 | std::string("Security.SafetyTips.OpenTime.") + action_suffix, |
| 64 | safety_tip_status), |
| 65 | base::Time::Now() - start_time, base::TimeDelta::FromMilliseconds(1), |
| 66 | base::TimeDelta::FromHours(1), 100); |
| 67 | } |
| 68 | |
| 69 | } // namespace |
| 70 | |
Aidan Beggs | e6a7dae7 | 2019-10-25 20:14:49 | [diff] [blame] | 71 | ReputationWebContentsObserver::~ReputationWebContentsObserver() = default; |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 72 | |
| 73 | void ReputationWebContentsObserver::DidFinishNavigation( |
| 74 | content::NavigationHandle* navigation_handle) { |
Joe DeBlasio | 7d60492 | 2019-08-08 19:56:36 | [diff] [blame] | 75 | if (!navigation_handle->IsInMainFrame() || |
Joe DeBlasio | 7f15aad | 2019-08-22 01:39:08 | [diff] [blame] | 76 | navigation_handle->IsSameDocument() || |
Aidan Beggs | e6a7dae7 | 2019-10-25 20:14:49 | [diff] [blame] | 77 | !navigation_handle->HasCommitted() || navigation_handle->IsErrorPage()) { |
| 78 | MaybeCallReputationCheckCallback(); |
Joe DeBlasio | 7f15aad | 2019-08-22 01:39:08 | [diff] [blame] | 79 | return; |
| 80 | } |
| 81 | |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 82 | last_navigation_safety_tip_info_ = {security_state::SafetyTipStatus::kNone, |
| 83 | GURL()}; |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 84 | last_safety_tip_navigation_entry_id_ = 0; |
| 85 | |
Joe DeBlasio | 7f15aad | 2019-08-22 01:39:08 | [diff] [blame] | 86 | MaybeShowSafetyTip(); |
| 87 | } |
| 88 | |
| 89 | void ReputationWebContentsObserver::OnVisibilityChanged( |
| 90 | content::Visibility visibility) { |
| 91 | MaybeShowSafetyTip(); |
| 92 | } |
| 93 | |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 94 | security_state::SafetyTipInfo |
| 95 | ReputationWebContentsObserver::GetSafetyTipInfoForVisibleNavigation() const { |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 96 | content::NavigationEntry* entry = |
| 97 | web_contents()->GetController().GetVisibleEntry(); |
| 98 | if (!entry) |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 99 | return {security_state::SafetyTipStatus::kUnknown, GURL()}; |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 100 | return last_safety_tip_navigation_entry_id_ == entry->GetUniqueID() |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 101 | ? last_navigation_safety_tip_info_ |
| 102 | : security_state::SafetyTipInfo( |
| 103 | {security_state::SafetyTipStatus::kNone, GURL()}); |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 104 | } |
| 105 | |
Emily Stark | 0790bb00 | 2019-08-31 04:25:43 | [diff] [blame] | 106 | void ReputationWebContentsObserver::RegisterReputationCheckCallbackForTesting( |
| 107 | base::OnceClosure callback) { |
| 108 | reputation_check_callback_for_testing_ = std::move(callback); |
| 109 | } |
| 110 | |
Joe DeBlasio | 7f15aad | 2019-08-22 01:39:08 | [diff] [blame] | 111 | ReputationWebContentsObserver::ReputationWebContentsObserver( |
| 112 | content::WebContents* web_contents) |
| 113 | : WebContentsObserver(web_contents), |
| 114 | profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 115 | weak_factory_(this) { |
| 116 | last_navigation_safety_tip_info_ = {security_state::SafetyTipStatus::kNone, |
| 117 | GURL()}; |
| 118 | } |
Joe DeBlasio | 7f15aad | 2019-08-22 01:39:08 | [diff] [blame] | 119 | |
| 120 | void ReputationWebContentsObserver::MaybeShowSafetyTip() { |
| 121 | if (web_contents()->GetMainFrame()->GetVisibilityState() != |
| 122 | content::PageVisibilityState::kVisible) { |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 123 | return; |
| 124 | } |
| 125 | |
| 126 | const GURL& url = web_contents()->GetLastCommittedURL(); |
| 127 | if (!url.SchemeIsHTTPOrHTTPS()) { |
| 128 | return; |
| 129 | } |
| 130 | |
| 131 | ReputationService* service = ReputationService::Get(profile_); |
| 132 | service->GetReputationStatus( |
| 133 | url, base::BindRepeating( |
| 134 | &ReputationWebContentsObserver::HandleReputationCheckResult, |
| 135 | weak_factory_.GetWeakPtr())); |
| 136 | } |
| 137 | |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 138 | void ReputationWebContentsObserver::HandleReputationCheckResult( |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 139 | ReputationCheckResult result) { |
Livvie Lin | d2539b4 | 2019-09-04 18:37:55 | [diff] [blame] | 140 | UMA_HISTOGRAM_ENUMERATION("Security.SafetyTips.SafetyTipShown", |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 141 | result.safety_tip_status); |
Livvie Lin | d2539b4 | 2019-09-04 18:37:55 | [diff] [blame] | 142 | |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 143 | if (result.safety_tip_status == security_state::SafetyTipStatus::kNone || |
| 144 | result.safety_tip_status == |
| 145 | security_state::SafetyTipStatus::kBadKeyword) { |
Emily Stark | 0790bb00 | 2019-08-31 04:25:43 | [diff] [blame] | 146 | MaybeCallReputationCheckCallback(); |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 147 | return; |
| 148 | } |
| 149 | |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 150 | if (result.user_previously_ignored) { |
Livvie Lin | d2539b4 | 2019-09-04 18:37:55 | [diff] [blame] | 151 | UMA_HISTOGRAM_ENUMERATION("Security.SafetyTips.SafetyTipIgnoredPageLoad", |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 152 | result.safety_tip_status); |
Emily Stark | 0790bb00 | 2019-08-31 04:25:43 | [diff] [blame] | 153 | MaybeCallReputationCheckCallback(); |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 154 | return; |
| 155 | } |
Livvie Lin | d2539b4 | 2019-09-04 18:37:55 | [diff] [blame] | 156 | |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 157 | // Set this field independent of whether the feature to show the UI is |
| 158 | // enabled/disabled. Metrics code uses this field and we want to record |
| 159 | // metrics regardless of the feature being enabled/disabled. |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 160 | last_navigation_safety_tip_info_ = {result.safety_tip_status, |
| 161 | result.suggested_url}; |
meacer | b66107d | 2019-10-17 20:00:19 | [diff] [blame] | 162 | |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 163 | // A navigation entry should always exist because reputation checks are only |
| 164 | // triggered when a committed navigation finishes. |
| 165 | last_safety_tip_navigation_entry_id_ = |
| 166 | web_contents()->GetController().GetLastCommittedEntry()->GetUniqueID(); |
Joe DeBlasio | 92c3003 | 2019-10-11 16:48:07 | [diff] [blame] | 167 | // Update the visible security state, since we downgrade indicator when a |
| 168 | // safety tip is triggered. This has to happen after |
| 169 | // last_safety_tip_navigation_entry_id_ is updated. |
| 170 | web_contents()->DidChangeVisibleSecurityState(); |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 171 | |
Emily Stark | 0790bb00 | 2019-08-31 04:25:43 | [diff] [blame] | 172 | MaybeCallReputationCheckCallback(); |
| 173 | |
Joe DeBlasio | 92c3003 | 2019-10-11 16:48:07 | [diff] [blame] | 174 | if (!base::FeatureList::IsEnabled(security_state::features::kSafetyTipUI)) { |
Emily Stark | ca844c0 | 2019-08-28 04:28:44 | [diff] [blame] | 175 | return; |
| 176 | } |
Emily Stark | a939e57 | 2019-09-05 23:18:08 | [diff] [blame] | 177 | ShowSafetyTipDialog( |
Aidan Beggs | be93a33 | 2019-10-28 17:29:41 | [diff] [blame] | 178 | web_contents(), result.safety_tip_status, result.url, |
| 179 | result.suggested_url, |
| 180 | base::BindOnce(OnSafetyTipClosed, result.safety_tip_status, |
| 181 | base::Time::Now())); |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 182 | } |
| 183 | |
Emily Stark | 0790bb00 | 2019-08-31 04:25:43 | [diff] [blame] | 184 | void ReputationWebContentsObserver::MaybeCallReputationCheckCallback() { |
| 185 | if (reputation_check_callback_for_testing_.is_null()) |
| 186 | return; |
| 187 | std::move(reputation_check_callback_for_testing_).Run(); |
| 188 | } |
| 189 | |
Joe DeBlasio | 1ed8640 | 2019-07-26 23:42:30 | [diff] [blame] | 190 | WEB_CONTENTS_USER_DATA_KEY_IMPL(ReputationWebContentsObserver) |