blob: 9fc16b198a2533e8fbbda6574be5b7f81b02e6ed [file] [log] [blame]
// Copyright 2013 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 <algorithm>
#include <ostream>
#include <sstream>
#include "base/json/json_writer.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"
namespace autofill {
namespace {
// Serializes a PasswordForm to a JSON object. Used only for logging in tests.
void PasswordFormToJSON(const PasswordForm& form,
base::DictionaryValue* target) {
target->SetInteger("scheme", form.scheme);
target->SetString("signon_realm", form.signon_realm);
target->SetBoolean("is_public_suffix_match", form.is_public_suffix_match);
target->SetBoolean("is_affiliation_based_match",
form.is_affiliation_based_match);
target->SetString("origin", form.origin.possibly_invalid_spec());
target->SetString("action", form.action.possibly_invalid_spec());
target->SetString("submit_element", form.submit_element);
target->SetBoolean("has_renderer_ids", form.has_renderer_ids);
target->SetString("username_element", form.username_element);
target->SetInteger("username_element_renderer_id",
form.username_element_renderer_id);
target->SetBoolean("username_marked_by_site", form.username_marked_by_site);
target->SetString("username_value", form.username_value);
target->SetString("password_elem", form.password_element);
target->SetString("password_value", form.password_value);
target->SetBoolean("password_value_is_default",
form.password_value_is_default);
target->SetString("new_password_element", form.new_password_element);
target->SetInteger("password_element_renderer_id",
form.password_element_renderer_id);
target->SetString("new_password_value", form.new_password_value);
target->SetBoolean("new_password_value_is_default",
form.new_password_value_is_default);
target->SetBoolean("new_password_marked_by_site",
form.new_password_marked_by_site);
target->SetString("other_possible_usernames",
ValueElementVectorToString(form.other_possible_usernames));
target->SetString("all_possible_passwords",
ValueElementVectorToString(form.all_possible_passwords));
target->SetBoolean("blacklisted", form.blacklisted_by_user);
target->SetBoolean("preferred", form.preferred);
target->SetDouble("date_created", form.date_created.ToDoubleT());
target->SetDouble("date_synced", form.date_synced.ToDoubleT());
target->SetInteger("type", form.type);
target->SetInteger("times_used", form.times_used);
std::ostringstream form_data_string_stream;
form_data_string_stream << form.form_data;
target->SetString("form_data", form_data_string_stream.str());
target->SetInteger("generation_upload_status", form.generation_upload_status);
target->SetString("display_name", form.display_name);
target->SetString("icon_url", form.icon_url.possibly_invalid_spec());
target->SetString("federation_origin", form.federation_origin.Serialize());
target->SetBoolean("skip_next_zero_click", form.skip_zero_click);
std::ostringstream layout_string_stream;
layout_string_stream << form.layout;
target->SetString("layout", layout_string_stream.str());
target->SetBoolean("was_parsed_using_autofill_predictions",
form.was_parsed_using_autofill_predictions);
target->SetString("affiliated_web_realm", form.affiliated_web_realm);
target->SetString("app_display_name", form.app_display_name);
target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
std::ostringstream submission_event_string_stream;
submission_event_string_stream << form.submission_event;
target->SetString("submission_event", submission_event_string_stream.str());
target->SetBoolean("only_for_fallback_saving", form.only_for_fallback_saving);
target->SetBoolean("is_gaia_with_skip_save_password_form",
form.is_gaia_with_skip_save_password_form);
}
} // namespace
PasswordForm::PasswordForm()
: scheme(SCHEME_HTML),
username_marked_by_site(false),
form_has_autofilled_value(false),
password_value_is_default(false),
new_password_value_is_default(false),
new_password_marked_by_site(false),
preferred(false),
blacklisted_by_user(false),
type(TYPE_MANUAL),
times_used(0),
generation_upload_status(NO_SIGNAL_SENT),
skip_zero_click(false),
layout(Layout::LAYOUT_OTHER),
was_parsed_using_autofill_predictions(false),
is_public_suffix_match(false),
is_affiliation_based_match(false),
submission_event(SubmissionIndicatorEvent::NONE),
only_for_fallback_saving(false),
is_gaia_with_skip_save_password_form(false) {}
PasswordForm::PasswordForm(const PasswordForm& other) = default;
PasswordForm::PasswordForm(PasswordForm&& other) = default;
PasswordForm::~PasswordForm() = default;
PasswordForm& PasswordForm::operator=(const PasswordForm& form) = default;
PasswordForm& PasswordForm::operator=(PasswordForm&& form) = default;
bool PasswordForm::IsPossibleChangePasswordForm() const {
return !new_password_element.empty() &&
layout != PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP;
}
bool PasswordForm::IsPossibleChangePasswordFormWithoutUsername() const {
return IsPossibleChangePasswordForm() && username_element.empty();
}
bool PasswordForm::operator==(const PasswordForm& form) const {
return scheme == form.scheme && signon_realm == form.signon_realm &&
origin == form.origin && action == form.action &&
submit_element == form.submit_element &&
has_renderer_ids == form.has_renderer_ids &&
username_element == form.username_element &&
username_element_renderer_id == form.username_element_renderer_id &&
username_marked_by_site == form.username_marked_by_site &&
username_value == form.username_value &&
other_possible_usernames == form.other_possible_usernames &&
all_possible_passwords == form.all_possible_passwords &&
form_has_autofilled_value == form.form_has_autofilled_value &&
password_element == form.password_element &&
password_element_renderer_id == form.password_element_renderer_id &&
password_value == form.password_value &&
new_password_element == form.new_password_element &&
new_password_marked_by_site == form.new_password_marked_by_site &&
new_password_value == form.new_password_value &&
preferred == form.preferred && date_created == form.date_created &&
date_synced == form.date_synced &&
blacklisted_by_user == form.blacklisted_by_user && type == form.type &&
times_used == form.times_used &&
form_data.SameFormAs(form.form_data) &&
generation_upload_status == form.generation_upload_status &&
display_name == form.display_name && icon_url == form.icon_url &&
// We compare the serialization of the origins here, as we want unique
// origins to compare as '=='.
federation_origin.Serialize() == form.federation_origin.Serialize() &&
skip_zero_click == form.skip_zero_click && layout == form.layout &&
was_parsed_using_autofill_predictions ==
form.was_parsed_using_autofill_predictions &&
is_public_suffix_match == form.is_public_suffix_match &&
is_affiliation_based_match == form.is_affiliation_based_match &&
affiliated_web_realm == form.affiliated_web_realm &&
app_display_name == form.app_display_name &&
app_icon_url == form.app_icon_url &&
submission_event == form.submission_event &&
only_for_fallback_saving == form.only_for_fallback_saving &&
is_gaia_with_skip_save_password_form ==
form.is_gaia_with_skip_save_password_form;
}
bool PasswordForm::operator!=(const PasswordForm& form) const {
return !operator==(form);
}
bool ArePasswordFormUniqueKeyEqual(const PasswordForm& left,
const PasswordForm& right) {
return (left.signon_realm == right.signon_realm &&
left.origin == right.origin &&
left.username_element == right.username_element &&
left.username_value == right.username_value &&
left.password_element == right.password_element);
}
bool LessThanUniqueKey::operator()(
const std::unique_ptr<PasswordForm>& left,
const std::unique_ptr<PasswordForm>& right) const {
int result = left->signon_realm.compare(right->signon_realm);
if (result)
return result < 0;
result = left->username_element.compare(right->username_element);
if (result)
return result < 0;
result = left->username_value.compare(right->username_value);
if (result)
return result < 0;
result = left->password_element.compare(right->password_element);
if (result)
return result < 0;
return left->origin < right->origin;
}
base::string16 ValueElementVectorToString(
const ValueElementVector& value_element_pairs) {
std::vector<base::string16> pairs(value_element_pairs.size());
std::transform(value_element_pairs.begin(), value_element_pairs.end(),
pairs.begin(), [](const ValueElementPair& p) {
return p.first + base::ASCIIToUTF16("+") + p.second;
});
return base::JoinString(pairs, base::ASCIIToUTF16(", "));
}
std::ostream& operator<<(std::ostream& os, PasswordForm::Layout layout) {
switch (layout) {
case PasswordForm::Layout::LAYOUT_OTHER:
os << "LAYOUT_OTHER";
break;
case PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP:
os << "LAYOUT_LOGIN_AND_SIGNUP";
break;
}
return os;
}
std::ostream& operator<<(std::ostream& os, const PasswordForm& form) {
base::DictionaryValue form_json;
PasswordFormToJSON(form, &form_json);
// Serialize the default PasswordForm, and remove values from the result that
// are equal to this to make the results more concise.
base::DictionaryValue default_form_json;
PasswordFormToJSON(PasswordForm(), &default_form_json);
for (base::DictionaryValue::Iterator it_default_key_values(default_form_json);
!it_default_key_values.IsAtEnd(); it_default_key_values.Advance()) {
const base::Value* actual_value;
if (form_json.Get(it_default_key_values.key(), &actual_value) &&
it_default_key_values.value().Equals(actual_value)) {
form_json.Remove(it_default_key_values.key(), nullptr);
}
}
std::string form_as_string;
base::JSONWriter::WriteWithOptions(
form_json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &form_as_string);
base::TrimWhitespaceASCII(form_as_string, base::TRIM_ALL, &form_as_string);
return os << "PasswordForm(" << form_as_string << ")";
}
std::ostream& operator<<(std::ostream& os, PasswordForm* form) {
return os << "&" << *form;
}
std::ostream& operator<<(
std::ostream& os,
PasswordForm::SubmissionIndicatorEvent submission_event) {
switch (submission_event) {
case PasswordForm::SubmissionIndicatorEvent::HTML_FORM_SUBMISSION:
os << "HTML_FORM_SUBMISSION";
break;
case PasswordForm::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION:
os << "SAME_DOCUMENT_NAVIGATION";
break;
case PasswordForm::SubmissionIndicatorEvent::XHR_SUCCEEDED:
os << "XHR_SUCCEEDED";
break;
case PasswordForm::SubmissionIndicatorEvent::FRAME_DETACHED:
os << "FRAME_DETACHED";
break;
case PasswordForm::SubmissionIndicatorEvent::MANUAL_SAVE:
os << "MANUAL_SAVE";
break;
case PasswordForm::SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR:
os << "DOM_MUTATION_AFTER_XHR";
break;
case PasswordForm::SubmissionIndicatorEvent::
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD:
os << "PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD";
break;
default:
os << "NO_SUBMISSION";
break;
}
return os;
}
} // namespace autofill