blob: b1d9e8ed263ac949cde5143f069902687d3fa542 [file] [log] [blame]
// Copyright 2017 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.
#import "ios/chrome/browser/ssl/insecure_input_tab_helper.h"
#import <Foundation/Foundation.h>
#include <memory>
#include "base/logging.h"
#include "components/security_state/ios/ssl_status_input_event_data.h"
#import "ios/web/public/navigation_item.h"
#import "ios/web/public/navigation_manager.h"
#import "ios/web/public/origin_util.h"
#include "ios/web/public/web_state/form_activity_params.h"
#import "ios/web/public/web_state/web_state.h"
#import "ios/web/public/web_state/web_state_user_data.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Creates or retrieves the |user_data| object in the SSLStatus attached to the
// WebState's NavigationItem.
security_state::SSLStatusInputEventData* GetOrCreateSSLStatusInputEventData(
web::WebState* web_state) {
web::NavigationItem* item =
web_state->GetNavigationManager()->GetLastCommittedItem();
// We aren't guaranteed to always have a navigation item.
if (!item)
return nullptr;
web::SSLStatus& ssl = item->GetSSL();
security_state::SSLStatusInputEventData* input_events =
static_cast<security_state::SSLStatusInputEventData*>(
ssl.user_data.get());
if (!input_events) {
ssl.user_data = std::make_unique<security_state::SSLStatusInputEventData>();
input_events = static_cast<security_state::SSLStatusInputEventData*>(
ssl.user_data.get());
}
return input_events;
}
} // namespace
DEFINE_WEB_STATE_USER_DATA_KEY(InsecureInputTabHelper);
InsecureInputTabHelper::~InsecureInputTabHelper() = default;
// static
InsecureInputTabHelper* InsecureInputTabHelper::GetOrCreateForWebState(
web::WebState* web_state) {
InsecureInputTabHelper* helper = FromWebState(web_state);
if (!helper) {
CreateForWebState(web_state);
helper = FromWebState(web_state);
DCHECK(helper);
}
return helper;
}
void InsecureInputTabHelper::DidShowPasswordFieldInInsecureContext() {
DCHECK(!web::IsOriginSecure(web_state_->GetLastCommittedURL()));
security_state::SSLStatusInputEventData* input_events =
GetOrCreateSSLStatusInputEventData(web_state_);
if (!input_events)
return;
// If the first password field for the web contents was just
// shown, update the SSLStatusInputEventData.
if (!input_events->input_events()->password_field_shown) {
input_events->input_events()->password_field_shown = true;
web_state_->DidChangeVisibleSecurityState();
}
}
void InsecureInputTabHelper::DidInteractWithNonsecureCreditCardInput() {
DCHECK(!web::IsOriginSecure(web_state_->GetLastCommittedURL()));
security_state::SSLStatusInputEventData* input_events =
GetOrCreateSSLStatusInputEventData(web_state_);
if (!input_events)
return;
// If the first credit card field for the web contents was just
// shown, update the SSLStatusInputEventData.
if (!input_events->input_events()->credit_card_field_edited) {
input_events->input_events()->credit_card_field_edited = true;
web_state_->DidChangeVisibleSecurityState();
}
}
void InsecureInputTabHelper::DidEditFieldInInsecureContext() {
DCHECK(!web::IsOriginSecure(web_state_->GetLastCommittedURL()));
security_state::SSLStatusInputEventData* input_events =
GetOrCreateSSLStatusInputEventData(web_state_);
if (!input_events)
return;
// If the first field edit in the web contents was just performed,
// update the SSLStatusInputEventData.
if (!input_events->input_events()->insecure_field_edited) {
input_events->input_events()->insecure_field_edited = true;
web_state_->DidChangeVisibleSecurityState();
}
}
InsecureInputTabHelper::InsecureInputTabHelper(web::WebState* web_state)
: web_state_(web_state) {
web_state_->AddObserver(this);
}
void InsecureInputTabHelper::FormActivityRegistered(
web::WebState* web_state,
const web::FormActivityParams& params) {
DCHECK_EQ(web_state_, web_state);
if (params.type == "input" &&
!web::IsOriginSecure(web_state->GetLastCommittedURL())) {
DidEditFieldInInsecureContext();
}
}
void InsecureInputTabHelper::WebStateDestroyed(web::WebState* web_state) {
DCHECK_EQ(web_state_, web_state);
web_state_->RemoveObserver(this);
web_state_ = nullptr;
}