| // 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 |