1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ssl/https_only_mode_tab_helper.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/reload_type.h"
#if !BUILDFLAG(IS_ANDROID)
#include "base/feature_list.h"
#include "chrome/browser/ssl/ask_before_http_dialog_controller.h"
#include "chrome/browser/ui/tabs/public/tab_features.h"
#include "components/security_interstitials/core/features.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"
#endif
namespace {
#if !BUILDFLAG(IS_ANDROID)
AskBeforeHttpDialogController* GetAskBeforeHttpDialogController(
content::WebContents* web_contents) {
// WebContentsObserver events can fire for things that aren't a tab and don't
// have a TabInterface associated.
// TODO(crbug.com/351990829): Filter these cases out before this gets called
// and then change this to call TabInterface::GetFromContents() instead.
auto* const tab = tabs::TabInterface::MaybeGetFromContents(web_contents);
if (!tab) {
return nullptr;
}
AskBeforeHttpDialogController* dialog_controller =
tab->GetTabFeatures()->ask_before_http_dialog_controller();
return dialog_controller;
}
#endif
} // namespace
HttpsOnlyModeTabHelper::~HttpsOnlyModeTabHelper() = default;
void HttpsOnlyModeTabHelper::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
#if !BUILDFLAG(IS_ANDROID)
if (base::FeatureList::IsEnabled(
security_interstitials::features::kHttpsFirstDialogUi)) {
// Close the Ask-before-HTTP dialog if a new navigation begins.
// TabDialogManager has a parameter to close tab-modal dialogs
// if a cross-site navigation occurs, but we need to be more
// strict and close on *any* new navigation. (For example, without
// this when a user clicks from badssl.com to http.badssl.com, sees
// the warning prompt, and then clicks the back button, the warning
// prompt would still be showing.)
auto* const dialog_controller =
GetAskBeforeHttpDialogController(navigation_handle->GetWebContents());
if (dialog_controller && dialog_controller->HasOpenDialogWidget()) {
// TODO(crbug.com/351990829): Consider adding a new `ClosedReason`
// value for this case.
dialog_controller->CloseDialogWidget(
views::Widget::ClosedReason::kUnspecified);
}
}
#endif
// If the user was on an exempt net error and the tab was reloaded, only
// reset the exempt error state, but keep the upgrade state so the reload
// will result in continuing to attempt the upgraded navigation (and if it
// later fails, the fallback will be to the original fallback URL).
bool should_maintain_upgrade_state =
is_exempt_error() &&
navigation_handle->GetReloadType() != content::ReloadType::NONE;
set_is_exempt_error(false);
if (!should_maintain_upgrade_state) {
set_fallback_url(GURL());
set_is_navigation_fallback(false);
set_is_navigation_upgraded(false);
}
}
void HttpsOnlyModeTabHelper::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
#if !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/351990829): Consider if this check could be made more
// precise. One option mght be to communicate a "interstitial enabled" flag on
// the helper which is set by the throttle.
// If dialog UI is enabled and this was a navigation cancelled by the
// throttle when we would interstitial the navigation, then trigger the
// dialog UI.
if (base::FeatureList::IsEnabled(
security_interstitials::features::kHttpsFirstDialogUi) &&
is_navigation_fallback_ &&
!navigation_handle->GetURL().SchemeIsCryptographic()) {
auto* const dialog_controller =
GetAskBeforeHttpDialogController(navigation_handle->GetWebContents());
if (!dialog_controller) {
// If there is no dialog controller, then the tab is being destroyed
// and there is nothing to show a modal on. Just return.
return;
}
ukm::SourceId ukm_source_id = ukm::ConvertToSourceId(
navigation_handle->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
dialog_controller->ShowDialog(navigation_handle->GetWebContents(),
navigation_handle->GetURL(), ukm_source_id);
// Make sure that the security indicator shows the correct icon.
// TODO(crbug.com/351990829): Add the new icon and integration.
navigation_handle->GetWebContents()->DidChangeVisibleSecurityState();
}
#endif
}
HttpsOnlyModeTabHelper::HttpsOnlyModeTabHelper(
content::WebContents* web_contents)
: WebContentsObserver(web_contents),
content::WebContentsUserData<HttpsOnlyModeTabHelper>(*web_contents) {}
WEB_CONTENTS_USER_DATA_KEY_IMPL(HttpsOnlyModeTabHelper);
|