blob: 859ab704173dcc1d6ea72f129c9ae21281293ebe [file] [log] [blame]
// Copyright 2014 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/autofill/core/common/save_password_progress_logger.h"
#include <algorithm>
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/common/password_form.h"
using base::checked_cast;
using base::Value;
using base::DictionaryValue;
namespace autofill {
namespace {
// Returns true for all characters which we don't want to see in the logged IDs
// or names of HTML elements.
bool IsUnwantedInElementID(char c) {
return !(c == '_' || c == '-' || base::IsAsciiAlpha(c) ||
base::IsAsciiDigit(c));
}
SavePasswordProgressLogger::StringID FormSchemeToStringID(
PasswordForm::Scheme scheme) {
switch (scheme) {
case PasswordForm::SCHEME_HTML:
return SavePasswordProgressLogger::STRING_SCHEME_HTML;
case PasswordForm::SCHEME_BASIC:
return SavePasswordProgressLogger::STRING_SCHEME_BASIC;
case PasswordForm::SCHEME_DIGEST:
return SavePasswordProgressLogger::STRING_SCHEME_DIGEST;
case PasswordForm::SCHEME_OTHER:
return SavePasswordProgressLogger::STRING_OTHER;
case PasswordForm::SCHEME_USERNAME_ONLY:
return SavePasswordProgressLogger::STRING_SCHEME_USERNAME_ONLY;
}
NOTREACHED();
return SavePasswordProgressLogger::STRING_INVALID;
}
} // namespace
SavePasswordProgressLogger::SavePasswordProgressLogger() {}
SavePasswordProgressLogger::~SavePasswordProgressLogger() {}
void SavePasswordProgressLogger::LogPasswordForm(
SavePasswordProgressLogger::StringID label,
const PasswordForm& form) {
DictionaryValue log;
log.SetString(GetStringFromID(STRING_SCHEME_MESSAGE),
GetStringFromID(FormSchemeToStringID(form.scheme)));
log.SetString(GetStringFromID(STRING_SCHEME_MESSAGE),
GetStringFromID(FormSchemeToStringID(form.scheme)));
log.SetString(GetStringFromID(STRING_SIGNON_REALM),
ScrubURL(GURL(form.signon_realm)));
log.SetString(GetStringFromID(STRING_ORIGIN), ScrubURL(form.origin));
log.SetString(GetStringFromID(STRING_ACTION), ScrubURL(form.action));
log.SetString(GetStringFromID(STRING_USERNAME_ELEMENT),
ScrubElementID(form.username_element));
log.SetString(GetStringFromID(STRING_PASSWORD_ELEMENT),
ScrubElementID(form.password_element));
log.SetString(GetStringFromID(STRING_NEW_PASSWORD_ELEMENT),
ScrubElementID(form.new_password_element));
log.SetBoolean(GetStringFromID(STRING_PASSWORD_GENERATED),
form.type == PasswordForm::TYPE_GENERATED);
log.SetInteger(GetStringFromID(STRING_TIMES_USED), form.times_used);
log.SetBoolean(GetStringFromID(STRING_PSL_MATCH),
form.is_public_suffix_match);
LogValue(label, log);
}
void SavePasswordProgressLogger::LogHTMLForm(
SavePasswordProgressLogger::StringID label,
const std::string& name_or_id,
const GURL& action) {
DictionaryValue log;
log.SetString(GetStringFromID(STRING_NAME_OR_ID), ScrubElementID(name_or_id));
log.SetString(GetStringFromID(STRING_ACTION), ScrubURL(action));
LogValue(label, log);
}
void SavePasswordProgressLogger::LogURL(
SavePasswordProgressLogger::StringID label,
const GURL& url) {
LogValue(label, Value(ScrubURL(url)));
}
void SavePasswordProgressLogger::LogBoolean(
SavePasswordProgressLogger::StringID label,
bool truth_value) {
LogValue(label, Value(truth_value));
}
void SavePasswordProgressLogger::LogNumber(
SavePasswordProgressLogger::StringID label,
int signed_number) {
LogValue(label, Value(signed_number));
}
void SavePasswordProgressLogger::LogNumber(
SavePasswordProgressLogger::StringID label,
size_t unsigned_number) {
LogNumber(label, checked_cast<int>(unsigned_number));
}
void SavePasswordProgressLogger::LogMessage(
SavePasswordProgressLogger::StringID message) {
LogValue(STRING_MESSAGE, Value(GetStringFromID(message)));
}
// static
std::string SavePasswordProgressLogger::ScrubURL(const GURL& url) {
if (url.is_valid())
return url.GetWithEmptyPath().spec();
return std::string();
}
void SavePasswordProgressLogger::LogValue(StringID label, const Value& log) {
std::string log_string;
bool conversion_to_string_successful = base::JSONWriter::WriteWithOptions(
log, base::JSONWriter::OPTIONS_PRETTY_PRINT, &log_string);
DCHECK(conversion_to_string_successful);
SendLog(GetStringFromID(label) + ": " + log_string);
}
// static
std::string SavePasswordProgressLogger::ScrubElementID(
const base::string16& element_id) {
return ScrubElementID(base::UTF16ToUTF8(element_id));
}
// static
std::string SavePasswordProgressLogger::ScrubElementID(std::string element_id) {
std::replace_if(element_id.begin(), element_id.end(), IsUnwantedInElementID,
'_');
return element_id;
}
// Note 1: Caching the ID->string map in an array would be probably faster, but
// the switch statement is (a) robust against re-ordering, and (b) checks in
// compile-time, that all IDs get a string assigned. The expected frequency of
// calls is low enough (in particular, zero if password manager internals page
// is not open), that optimizing for code robustness is preferred against speed.
// Note 2: Do not use '.' in the message strings -- the ending of the log items
// should be controlled by the logger. Also, some of the messages below can be
// used as dictionary keys.
//
// static
std::string SavePasswordProgressLogger::GetStringFromID(
SavePasswordProgressLogger::StringID id) {
switch (id) {
case SavePasswordProgressLogger::STRING_DECISION_ASK:
return "Decision: ASK the user";
case SavePasswordProgressLogger::STRING_DECISION_DROP:
return "Decision: DROP the password";
case SavePasswordProgressLogger::STRING_DECISION_SAVE:
return "Decision: SAVE the password";
case SavePasswordProgressLogger::STRING_OTHER:
return "(other)";
case SavePasswordProgressLogger::STRING_SCHEME_HTML:
return "HTML";
case SavePasswordProgressLogger::STRING_SCHEME_BASIC:
return "Basic";
case SavePasswordProgressLogger::STRING_SCHEME_DIGEST:
return "Digest";
case SavePasswordProgressLogger::STRING_SCHEME_USERNAME_ONLY:
return "Username only";
case SavePasswordProgressLogger::STRING_SCHEME_MESSAGE:
return "Scheme";
case SavePasswordProgressLogger::STRING_SIGNON_REALM:
return "Signon realm";
case SavePasswordProgressLogger::STRING_ORIGIN:
return "Origin";
case SavePasswordProgressLogger::STRING_ACTION:
return "Action";
case SavePasswordProgressLogger::STRING_USERNAME_ELEMENT:
return "Username element";
case SavePasswordProgressLogger::STRING_PASSWORD_ELEMENT:
return "Password element";
case SavePasswordProgressLogger::STRING_NEW_PASSWORD_ELEMENT:
return "New password element";
case SavePasswordProgressLogger::STRING_PASSWORD_GENERATED:
return "Password generated";
case SavePasswordProgressLogger::STRING_TIMES_USED:
return "Times used";
case SavePasswordProgressLogger::STRING_PSL_MATCH:
return "PSL match";
case SavePasswordProgressLogger::STRING_NAME_OR_ID:
return "Form name or ID";
case SavePasswordProgressLogger::STRING_MESSAGE:
return "Message";
case SavePasswordProgressLogger::STRING_SET_AUTH_METHOD:
return "LoginHandler::SetAuth";
case SavePasswordProgressLogger::STRING_AUTHENTICATION_HANDLED:
return "Authentication already handled";
case SavePasswordProgressLogger::STRING_LOGINHANDLER_FORM:
return "LoginHandler reports this form";
case SavePasswordProgressLogger::STRING_SEND_PASSWORD_FORMS_METHOD:
return "PasswordAutofillAgent::SendPasswordForms";
case SavePasswordProgressLogger::STRING_SECURITY_ORIGIN:
return "Security origin";
case SavePasswordProgressLogger::STRING_SECURITY_ORIGIN_FAILURE:
return "Security origin cannot access password manager";
case SavePasswordProgressLogger::STRING_WEBPAGE_EMPTY:
return "Webpage is empty";
case SavePasswordProgressLogger::STRING_NUMBER_OF_ALL_FORMS:
return "Number of all forms";
case SavePasswordProgressLogger::STRING_FORM_FOUND_ON_PAGE:
return "Form found on page";
case SavePasswordProgressLogger::STRING_FORM_IS_VISIBLE:
return "Form is visible";
case SavePasswordProgressLogger::STRING_FORM_IS_PASSWORD:
return "Form is a password form";
case SavePasswordProgressLogger::STRING_FORM_IS_NOT_PASSWORD:
return "Form isn't a password form";
case SavePasswordProgressLogger::STRING_WILL_SUBMIT_FORM_METHOD:
return "PasswordAutofillAgent::WillSubmitForm";
case SavePasswordProgressLogger::STRING_HTML_FORM_FOR_SUBMIT:
return "HTML form for submit";
case SavePasswordProgressLogger::STRING_CREATED_PASSWORD_FORM:
return "Created PasswordForm";
case SavePasswordProgressLogger::STRING_SUBMITTED_PASSWORD_REPLACED:
return "Submitted password replaced with the provisionally saved one";
case SavePasswordProgressLogger::STRING_DID_START_PROVISIONAL_LOAD_METHOD:
return "PasswordAutofillAgent::DidStartProvisionalLoad";
case SavePasswordProgressLogger::STRING_FRAME_NOT_MAIN_FRAME:
return "|frame| is not the main frame";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME:
return "provisionally_saved_forms_[form_frame]";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD:
return "PasswordManager::ProvisionallySavePassword";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM:
return "ProvisionallySavePassword form";
case SavePasswordProgressLogger::STRING_IS_SAVING_ENABLED:
return "IsSavingAndFillingEnabledForCurrentPage";
case SavePasswordProgressLogger::STRING_EMPTY_PASSWORD:
return "Empty password";
case SavePasswordProgressLogger::STRING_EXACT_MATCH:
return "Form manager found, exact match";
case SavePasswordProgressLogger::STRING_MATCH_WITHOUT_ACTION:
return "Form manager found, match except for action";
case SavePasswordProgressLogger::STRING_ORIGINS_MATCH:
return "Form manager found, only origins match";
case SavePasswordProgressLogger::STRING_MATCHING_NOT_COMPLETE:
return "No form manager has completed matching";
case SavePasswordProgressLogger::STRING_FORM_BLACKLISTED:
return "Form blacklisted";
case SavePasswordProgressLogger::STRING_INVALID_FORM:
return "Invalid form";
case SavePasswordProgressLogger::STRING_SYNC_CREDENTIAL:
return "Credential is used for syncing passwords";
case STRING_BLOCK_PASSWORD_SAME_ORIGIN_INSECURE_SCHEME:
return "Blocked password due to same origin but insecure scheme";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM:
return "provisionally_saved_form";
case SavePasswordProgressLogger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD:
return "PasswordManager::OnPasswordFormsRendered";
case SavePasswordProgressLogger::STRING_ON_SAME_DOCUMENT_NAVIGATION:
return "PasswordManager::OnSameDocumentNavigation";
case SavePasswordProgressLogger::STRING_ON_ASK_USER_OR_SAVE_PASSWORD:
return "PasswordManager::AskUserOrSavePassword";
case SavePasswordProgressLogger::STRING_CAN_PROVISIONAL_MANAGER_SAVE_METHOD:
return "PasswordManager::CanProvisionalManagerSave";
case SavePasswordProgressLogger::STRING_NO_PROVISIONAL_SAVE_MANAGER:
return "No provisional save manager";
case SavePasswordProgressLogger::STRING_NUMBER_OF_VISIBLE_FORMS:
return "Number of visible forms";
case SavePasswordProgressLogger::STRING_PASSWORD_FORM_REAPPEARED:
return "Password form re-appeared";
case SavePasswordProgressLogger::STRING_SAVING_DISABLED:
return "Saving disabled";
case SavePasswordProgressLogger::STRING_NO_MATCHING_FORM:
return "No matching form";
case SavePasswordProgressLogger::STRING_SSL_ERRORS_PRESENT:
return "SSL errors present";
case SavePasswordProgressLogger::STRING_ONLY_VISIBLE:
return "only_visible";
case SavePasswordProgressLogger::STRING_SHOW_PASSWORD_PROMPT:
return "Show password prompt";
case SavePasswordProgressLogger::STRING_PASSWORDMANAGER_AUTOFILL:
return "PasswordManager::Autofill";
case SavePasswordProgressLogger::STRING_PASSWORDMANAGER_AUTOFILLHTTPAUTH:
return "PasswordManager::AutofillHttpAuth";
case SavePasswordProgressLogger::
STRING_PASSWORDMANAGER_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS:
return "PasswordManager::ShowInitialPasswordAccountSuggestions";
case SavePasswordProgressLogger::STRING_WAIT_FOR_USERNAME:
return "wait_for_username";
case SavePasswordProgressLogger::STRING_LOGINMODELOBSERVER_PRESENT:
return "Instances of LoginModelObserver may be present";
case SavePasswordProgressLogger::
STRING_WAS_LAST_NAVIGATION_HTTP_ERROR_METHOD:
return "ChromePasswordManagerClient::WasLastNavigationHTTPError";
case SavePasswordProgressLogger::STRING_HTTP_STATUS_CODE:
return "HTTP status code for landing page";
case SavePasswordProgressLogger::
STRING_PROVISIONALLY_SAVED_FORM_IS_NOT_HTML:
return "Provisionally saved form is not HTML";
case SavePasswordProgressLogger::STRING_PROCESS_MATCHES_METHOD:
return "PasswordFormManager::ProcessMatches";
case SavePasswordProgressLogger::STRING_BEST_SCORE:
return "best_score";
case SavePasswordProgressLogger::STRING_ON_GET_STORE_RESULTS_METHOD:
return "FormFetcherImpl::OnGetPasswordStoreResults";
case SavePasswordProgressLogger::STRING_NUMBER_RESULTS:
return "Number of results from the password store";
case SavePasswordProgressLogger::STRING_FETCH_METHOD:
return "FormFetcherImpl::Fetch";
case SavePasswordProgressLogger::STRING_NO_STORE:
return "PasswordStore is not available";
case SavePasswordProgressLogger::STRING_CREATE_LOGIN_MANAGERS_METHOD:
return "PasswordManager::CreatePendingLoginManagers";
case SavePasswordProgressLogger::STRING_OLD_NUMBER_LOGIN_MANAGERS:
return "Number of pending login managers (before)";
case SavePasswordProgressLogger::STRING_NEW_NUMBER_LOGIN_MANAGERS:
return "Number of pending login managers (after)";
case SavePasswordProgressLogger::
STRING_PASSWORD_MANAGEMENT_ENABLED_FOR_CURRENT_PAGE:
return "IsPasswordManagementEnabledForCurrentPage";
case SavePasswordProgressLogger::STRING_SHOW_LOGIN_PROMPT_METHOD:
return "ShowLoginPrompt";
case SavePasswordProgressLogger::STRING_NEW_UI_STATE:
return "The new state of the UI";
case SavePasswordProgressLogger::STRING_FORM_NOT_AUTOFILLED:
return "The observed form will not be autofilled";
case SavePasswordProgressLogger::STRING_CHANGE_PASSWORD_FORM:
return "Not saving password for a change password form";
case SavePasswordProgressLogger::STRING_PROCESS_FRAME_METHOD:
return "PasswordFormManager::ProcessFrame";
case SavePasswordProgressLogger::STRING_FORM_SIGNATURE:
return "Signature of form";
case SavePasswordProgressLogger::STRING_FORM_FETCHER_STATE:
return "FormFetcherImpl::state_";
case SavePasswordProgressLogger::STRING_ADDING_SIGNATURE:
return "Adding manager for form";
case SavePasswordProgressLogger::STRING_UNOWNED_INPUTS_VISIBLE:
return "Some control elements not associated to a form element are "
"visible";
case SavePasswordProgressLogger::STRING_ON_FILL_PASSWORD_FORM_METHOD:
return "PasswordAutofillAgent::OnFillPasswordForm";
case SavePasswordProgressLogger::
STRING_ON_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS:
return "AutofillAgent::OnShowInitialPasswordAccountSuggestions";
case SavePasswordProgressLogger::STRING_AMBIGUOUS_OR_EMPTY_NAMES:
return "ambiguous_or_empty_names";
case SavePasswordProgressLogger::STRING_NUMBER_OF_POTENTIAL_FORMS_TO_FILL:
return "Number of potential forms to fill";
case SavePasswordProgressLogger::STRING_CONTAINS_FILLABLE_USERNAME_FIELD:
return "form_contains_fillable_username_field";
case SavePasswordProgressLogger::STRING_USERNAME_FIELD_NAME_EMPTY:
return "username_field_name empty";
case SavePasswordProgressLogger::STRING_PASSWORD_FIELD_NAME_EMPTY:
return "password_field_name empty";
case SavePasswordProgressLogger::STRING_FORM_DATA_WAIT:
return "form_data's wait_for_username";
case SavePasswordProgressLogger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD:
return "FillUserNameAndPassword in PasswordAutofillAgent";
case SavePasswordProgressLogger::STRING_USERNAMES_MATCH:
return "Username to fill matches that on the page";
case SavePasswordProgressLogger::STRING_MATCH_IN_ADDITIONAL:
return "Match found in additional logins";
case SavePasswordProgressLogger::STRING_USERNAME_FILLED:
return "Filled username element named";
case SavePasswordProgressLogger::STRING_PASSWORD_FILLED:
return "Filled password element named";
case SavePasswordProgressLogger::STRING_FORM_NAME:
return "Form name";
case SavePasswordProgressLogger::STRING_FIELDS:
return "Form fields";
case SavePasswordProgressLogger::STRING_SERVER_PREDICTIONS:
return "Server predictions";
case SavePasswordProgressLogger::STRING_FORM_VOTES:
return "Form votes";
case SavePasswordProgressLogger::STRING_REUSE_FOUND:
return "Password reused from ";
case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_SAVING_DISABLED:
return "Generation disabled: saving disabled";
case SavePasswordProgressLogger::STRING_GENERATION_DISABLED_NO_SYNC:
return "Generation disabled: no sync";
case STRING_GENERATION_RENDERER_ENABLED:
return "Generation renderer enabled";
case STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM:
return "Generation invalid PasswordForm";
case STRING_GENERATION_RENDERER_POSSIBLE_ACCOUNT_CREATION_FORMS:
return "Generation possible account creation forms";
case STRING_GENERATION_RENDERER_NO_PASSWORD_MANAGER_ACCESS:
return "Generation: no PasswordManager access";
case STRING_GENERATION_RENDERER_FORM_ALREADY_FOUND:
return "Generation: account creation form already found";
case STRING_GENERATION_RENDERER_NO_POSSIBLE_CREATION_FORMS:
return "Generation: no possible account creation forms";
case STRING_GENERATION_RENDERER_NOT_BLACKLISTED:
return "Generation: no non-blacklisted confirmation";
case STRING_GENERATION_RENDERER_AUTOCOMPLETE_ATTRIBUTE:
return "Generation: autocomplete attributes found";
case STRING_GENERATION_RENDERER_NO_SERVER_SIGNAL:
return "Generation: no server signal";
case STRING_GENERATION_RENDERER_ELIGIBLE_FORM_FOUND:
return "Generation: eligible form found";
case STRING_GENERATION_RENDERER_NO_FIELD_FOUND:
return "Generation: fields for generation are not found";
case STRING_GENERATION_RENDERER_AUTOMATIC_GENERATION_AVAILABLE:
return "Generation: automatic generation is available";
case STRING_GENERATION_RENDERER_SHOW_MANUAL_GENERATION_POPUP:
return "Show generation popup triggered manually";
case STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED:
return "Generated password accepted";
case STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT:
return "Successful submission indicator event";
case STRING_MAIN_FRAME_ORIGIN:
return "Main frame origin";
case STRING_IS_FORM_TAG:
return "Form with form tag";
case STRING_FORM_PARSING_INPUT:
return "Form parsing input";
case STRING_FORM_PARSING_OUTPUT:
return "Form parsing output";
case SavePasswordProgressLogger::STRING_INVALID:
return "INVALID";
// Intentionally no default: clause here -- all IDs need to get covered.
}
NOTREACHED(); // Win compilers don't believe this is unreachable.
return std::string();
}
} // namespace autofill