| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h" |
| |
| #import "base/logging.h" |
| #import "base/strings/string_number_conversions.h" |
| #import "base/values.h" |
| #import "ios/components/security_interstitials/ios_security_interstitial_page.h" |
| #import "ios/web/public/navigation/navigation_context.h" |
| #import "ios/web/public/web_state.h" |
| #import "ios/web/public/web_state_user_data.h" |
| |
| namespace security_interstitials { |
| |
| #pragma mark - IOSBlockingPageTabHelper |
| |
| IOSBlockingPageTabHelper::IOSBlockingPageTabHelper(web::WebState* web_state) |
| : navigation_id_listener_(web_state, this) {} |
| |
| IOSBlockingPageTabHelper::~IOSBlockingPageTabHelper() = default; |
| |
| void IOSBlockingPageTabHelper::AssociateBlockingPage( |
| int64_t navigation_id, |
| std::unique_ptr<IOSSecurityInterstitialPage> blocking_page) { |
| if (navigation_id == last_committed_navigation_id_) { |
| blocking_page_for_currently_committed_navigation_ = |
| std::move(blocking_page); |
| } else { |
| blocking_pages_for_navigations_[navigation_id] = std::move(blocking_page); |
| } |
| } |
| |
| bool IOSBlockingPageTabHelper::ShouldDisplayURL() const { |
| return blocking_page_for_currently_committed_navigation_->ShouldDisplayURL(); |
| } |
| |
| IOSSecurityInterstitialPage* IOSBlockingPageTabHelper::GetCurrentBlockingPage() |
| const { |
| return blocking_page_for_currently_committed_navigation_.get(); |
| } |
| |
| void IOSBlockingPageTabHelper::OnBlockingPageCommandReceived( |
| SecurityInterstitialCommand command) { |
| if (!blocking_page_for_currently_committed_navigation_) { |
| return; |
| } |
| |
| blocking_page_for_currently_committed_navigation_->HandleCommand(command); |
| } |
| |
| void IOSBlockingPageTabHelper::UpdateForBlockingPageDismissed() { |
| blocking_page_for_currently_committed_navigation_->WasDismissed(); |
| } |
| |
| void IOSBlockingPageTabHelper::UpdateForFinishedNavigation( |
| int64_t navigation_id, |
| bool committed) { |
| if (committed) { |
| last_committed_navigation_id_ = navigation_id; |
| blocking_page_for_currently_committed_navigation_ = |
| std::move(blocking_pages_for_navigations_[navigation_id]); |
| } |
| blocking_pages_for_navigations_.erase(navigation_id); |
| } |
| |
| #pragma mark - IOSBlockingPageTabHelper::CommittedNavigationIDListener |
| |
| IOSBlockingPageTabHelper::CommittedNavigationIDListener:: |
| CommittedNavigationIDListener(web::WebState* web_state, |
| IOSBlockingPageTabHelper* tab_helper) |
| : tab_helper_(tab_helper) { |
| DCHECK(tab_helper_); |
| scoped_observation_.Observe(web_state); |
| } |
| |
| IOSBlockingPageTabHelper::CommittedNavigationIDListener:: |
| ~CommittedNavigationIDListener() = default; |
| |
| void IOSBlockingPageTabHelper::CommittedNavigationIDListener:: |
| DidStartNavigation(web::WebState* web_state, |
| web::NavigationContext* navigation_context) { |
| IOSSecurityInterstitialPage* page = tab_helper_->GetCurrentBlockingPage(); |
| if (page && (navigation_context->GetPageTransition() & |
| ui::PAGE_TRANSITION_FORWARD_BACK)) { |
| // Interstitial page would be the last page shown so looking for this page |
| // transition would mean that a user is using the back button and is |
| // leaving the interstitial page. |
| tab_helper_->UpdateForBlockingPageDismissed(); |
| } |
| } |
| |
| void IOSBlockingPageTabHelper::CommittedNavigationIDListener:: |
| DidFinishNavigation(web::WebState* web_state, |
| web::NavigationContext* navigation_context) { |
| if (navigation_context->IsSameDocument()) { |
| return; |
| } |
| |
| tab_helper_->UpdateForFinishedNavigation( |
| navigation_context->GetNavigationId(), |
| navigation_context->HasCommitted()); |
| |
| // Interstitials may change the visibility of the URL or other security state. |
| web_state->DidChangeVisibleSecurityState(); |
| |
| IOSSecurityInterstitialPage* page = tab_helper_->GetCurrentBlockingPage(); |
| if (!page) { |
| // `page` will be null if a IOSSecurityInterstitialPage is not being |
| // displayed to the user. |
| return; |
| } |
| page->ShowInfobar(); |
| } |
| |
| void IOSBlockingPageTabHelper::CommittedNavigationIDListener::WebStateDestroyed( |
| web::WebState* web_state) { |
| DCHECK(scoped_observation_.IsObservingSource(web_state)); |
| scoped_observation_.Reset(); |
| |
| IOSSecurityInterstitialPage* page = tab_helper_->GetCurrentBlockingPage(); |
| if (page) { |
| // Logs closing the tab as `DONT_PROCEED` since an interstitial page is |
| // being dismissed. |
| tab_helper_->UpdateForBlockingPageDismissed(); |
| } |
| } |
| |
| } // namespace security_interstitials |