blob: 564182d372d30d8ac17c0665a09cc64c67fb74a1 [file] [log] [blame]
// Copyright 2018 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.
#include "components/password_manager/core/browser/password_form_filling.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/common/password_manager_features.h"
using autofill::PasswordForm;
using autofill::PasswordFormFillData;
using Logger = autofill::SavePasswordProgressLogger;
namespace password_manager {
namespace {
bool PreferredRealmIsFromAndroid(const PasswordFormFillData& fill_data) {
return FacetURI::FromPotentiallyInvalidSpec(fill_data.preferred_realm)
.IsValidAndroidFacetURI();
}
bool ContainsAndroidCredentials(const PasswordFormFillData& fill_data) {
for (const auto& login : fill_data.additional_logins) {
if (FacetURI::FromPotentiallyInvalidSpec(login.second.realm)
.IsValidAndroidFacetURI()) {
return true;
}
}
return PreferredRealmIsFromAndroid(fill_data);
}
bool IsFillOnAccountSelectFeatureEnabled() {
return base::FeatureList::IsEnabled(
password_manager::features::kFillOnAccountSelect);
}
void Autofill(PasswordManagerClient* client,
PasswordManagerDriver* driver,
const PasswordForm& form_for_autofill,
const std::vector<const PasswordForm*>& best_matches,
const std::vector<const PasswordForm*>& federated_matches,
const PasswordForm& preferred_match,
bool wait_for_username) {
DCHECK_EQ(PasswordForm::Scheme::kHtml, preferred_match.scheme);
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client)) {
logger.reset(
new BrowserSavePasswordProgressLogger(client->GetLogManager()));
logger->LogMessage(Logger::STRING_PASSWORDMANAGER_AUTOFILL);
}
PasswordFormFillData fill_data(form_for_autofill, best_matches,
preferred_match, wait_for_username);
if (logger)
logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username);
UMA_HISTOGRAM_BOOLEAN(
"PasswordManager.FillSuggestionsIncludeAndroidAppCredentials",
ContainsAndroidCredentials(fill_data));
metrics_util::LogFilledCredentialIsFromAndroidApp(
PreferredRealmIsFromAndroid(fill_data));
driver->FillPasswordForm(fill_data);
client->PasswordWasAutofilled(best_matches, form_for_autofill.origin,
&federated_matches);
}
} // namespace
LikelyFormFilling SendFillInformationToRenderer(
PasswordManagerClient* client,
PasswordManagerDriver* driver,
const PasswordForm& observed_form,
const std::vector<const PasswordForm*>& best_matches,
const std::vector<const PasswordForm*>& federated_matches,
const PasswordForm* preferred_match,
PasswordFormMetricsRecorder* metrics_recorder) {
DCHECK(driver);
DCHECK_EQ(PasswordForm::Scheme::kHtml, observed_form.scheme);
if (autofill::IsShowAutofillSignaturesEnabled()) {
driver->AnnotateFieldsWithParsingResult(
{.username_renderer_id = observed_form.username_element_renderer_id,
.password_renderer_id = observed_form.password_element_renderer_id,
.new_password_renderer_id =
observed_form.new_password_element_renderer_id,
.confirm_password_renderer_id =
observed_form.confirmation_password_element_renderer_id});
}
if (best_matches.empty()) {
driver->InformNoSavedCredentials();
metrics_recorder->RecordFillEvent(
PasswordFormMetricsRecorder::kManagerFillEventNoCredential);
return LikelyFormFilling::kNoFilling;
}
DCHECK(preferred_match);
// If the parser of the PasswordFormManager decides that there is no
// current password field, no filling attempt will be made. In this case the
// renderer won't treat this as the "first filling" and won't record metrics
// accordingly. The browser should not do that either.
const bool no_sign_in_form =
!observed_form.HasPasswordElement() && !observed_form.IsSingleUsername();
// Wait for the username before filling passwords in case the
// FillOnAccountSelectHttp feature is active and the main frame is
// insecure.
const bool enable_foas_on_http =
base::FeatureList::IsEnabled(features::kFillOnAccountSelectHttp) &&
!client->IsMainFrameSecure();
// Proceed to autofill.
// Note that we provide the choices but don't actually prefill a value if:
// (1) we are in Incognito mode, or
// (2) if it matched using public suffix domain matching, or
// (3) it would result in unexpected filling in a form with new password
// fields.
// (4) the current main frame origin is insecure and the FOAS on HTTP feature
// is active.
using WaitForUsernameReason =
PasswordFormMetricsRecorder::WaitForUsernameReason;
WaitForUsernameReason wait_for_username_reason =
WaitForUsernameReason::kDontWait;
if (client->IsIncognito()) {
wait_for_username_reason = WaitForUsernameReason::kIncognitoMode;
} else if (preferred_match->is_public_suffix_match) {
wait_for_username_reason = WaitForUsernameReason::kPublicSuffixMatch;
} else if (no_sign_in_form) {
// If the parser did not find a current password element, don't fill.
wait_for_username_reason = WaitForUsernameReason::kFormNotGoodForFilling;
} else if (enable_foas_on_http) {
wait_for_username_reason = WaitForUsernameReason::kFoasOnHTTP;
} else if (autofill::IsTouchToFillEnabled()) {
wait_for_username_reason = WaitForUsernameReason::kTouchToFill;
} else if (IsFillOnAccountSelectFeatureEnabled()) {
wait_for_username_reason = WaitForUsernameReason::kFoasFeature;
}
// Record no "FirstWaitForUsernameReason" metrics for a form that is not meant
// for filling. The renderer won't record a "FirstFillingResult" either.
if (!no_sign_in_form) {
metrics_recorder->RecordFirstWaitForUsernameReason(
wait_for_username_reason);
}
bool wait_for_username =
wait_for_username_reason != WaitForUsernameReason::kDontWait;
if (wait_for_username) {
metrics_recorder->SetManagerAction(
PasswordFormMetricsRecorder::kManagerActionNone);
metrics_recorder->RecordFillEvent(
PasswordFormMetricsRecorder::kManagerFillEventBlockedOnInteraction);
} else {
metrics_recorder->SetManagerAction(
PasswordFormMetricsRecorder::kManagerActionAutofilled);
metrics_recorder->RecordFillEvent(
PasswordFormMetricsRecorder::kManagerFillEventAutofilled);
base::RecordAction(base::UserMetricsAction("PasswordManager_Autofilled"));
}
// Continue with autofilling any password forms as traditionally has been
// done.
Autofill(client, driver, observed_form, best_matches, federated_matches,
*preferred_match, wait_for_username);
return wait_for_username ? LikelyFormFilling::kFillOnAccountSelect
: LikelyFormFilling::kFillOnPageLoad;
}
} // namespace password_manager