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

#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
#define COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/time/time.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace autofill {

// Pair of a value and the name of the element that contained this value.
using ValueElementPair = std::pair<base::string16, base::string16>;

// Vector of possible username values and corresponding field names.
using ValueElementVector = std::vector<ValueElementPair>;

// The PasswordForm struct encapsulates information about a login form,
// which can be an HTML form or a dialog with username/password text fields.
//
// The Web Data database stores saved username/passwords and associated form
// metdata using a PasswordForm struct, typically one that was created from
// a parsed HTMLFormElement or LoginDialog, but the saved entries could have
// also been created by imported data from another browser.
//
// The PasswordManager implements a fuzzy-matching algorithm to compare saved
// PasswordForm entries against PasswordForms that were created from a parsed
// HTML or dialog form. As one might expect, the more data contained in one
// of the saved PasswordForms, the better the job the PasswordManager can do
// in matching it against the actual form it was saved on, and autofill
// accurately. But it is not always possible, especially when importing from
// other browsers with different data models, to copy over all the information
// about a particular "saved password entry" to our PasswordForm
// representation.
//
// The field descriptions in the struct specification below are intended to
// describe which fields are not strictly required when adding a saved password
// entry to the database and how they can affect the matching process.

struct PasswordForm {
  using Scheme = mojom::PasswordForm_Scheme;
  using Type = mojom::PasswordForm_Type;
  using GenerationUploadStatus = mojom::PasswordForm_GenerationUploadStatus;

  Scheme scheme = Scheme::kHtml;

  // The "Realm" for the sign-on. This is scheme, host, port for SCHEME_HTML.
  // Dialog based forms also contain the HTTP realm. Android based forms will
  // contain a string of the form "android://<hash of cert>@<package name>"
  //
  // The signon_realm is effectively the primary key used for retrieving
  // data from the database, so it must not be empty.
  std::string signon_realm;

  // An origin URL consists of the scheme, host, port and path; the rest is
  // stripped. This is the primary data used by the PasswordManager to decide
  // (in longest matching prefix fashion) whether or not a given PasswordForm
  // result from the database is a good fit for a particular form on a page.
  // This should not be empty except for Android based credentials.
  // TODO(melandory): origin should be renamed in order to be consistent with
  // GURL definition of origin.
  GURL origin;

  // The action target of the form; like |origin| URL consists of the scheme,
  // host, port and path; the rest is stripped. This is the primary data used by
  // the PasswordManager for form autofill; that is, the action of the saved
  // credentials must match the action of the form on the page to be autofilled.
  // If this is empty / not available, it will result in a "restricted" IE-like
  // autofill policy, where we wait for the user to type in their username
  // before autofilling the password. In these cases, after successful login the
  // action URL will automatically be assigned by the PasswordManager.
  //
  // When parsing an HTML form, this must always be set.
  GURL action;

  // The web realm affiliated with the Android application, if the form is an
  // Android credential. Otherwise, the string is empty. If there are several
  // realms affiliated with the application, an arbitrary realm is chosen. The
  // field is filled out when the PasswordStore injects affiliation and branding
  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
  // no prior call to this method, the string is empty.
  std::string affiliated_web_realm;

  // The display name (e.g. Play Store name) of the Android application if the
  // form is an Android credential. Otherwise, the string is empty. The field is
  // filled out when the PasswordStore injects affiliation and branding
  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
  // no prior call to this method, the string is empty.
  std::string app_display_name;

  // The icon URL (e.g. Play Store icon URL) of the Android application if the
  // form is an Android credential. Otherwise, the URL is empty. The field is
  // filled out when the PasswordStore injects affiliation and branding
  // information, i.e. in InjectAffiliationAndBrandingInformation. If there was
  // no prior call to this method, the URL is empty.
  GURL app_icon_url;

  // The name of the submit button used. Optional; only used in scoring
  // of PasswordForm results from the database to make matches as tight as
  // possible.
  //
  // When parsing an HTML form, this must always be set.
  base::string16 submit_element;

  // True if renderer ids for username and password fields are present. Only set
  // on form parsing, and not persisted.
  // TODO(https://crbug.com/831123): Remove this field when old parsing is
  // removed and filling by renderer ids is by default.
  bool has_renderer_ids = false;

  // The name of the username input element. Optional (improves scoring).
  //
  // When parsing an HTML form, this must always be set.
  base::string16 username_element;

  // The renderer id of the username input element. It is set during the new
  // form parsing and not persisted.
  uint32_t username_element_renderer_id =
      FormFieldData::kNotSetFormControlRendererId;

  // True if the server-side classification believes that the field may be
  // pre-filled with a placeholder in the value attribute. It is set during
  // form parsing and not persisted.
  bool username_may_use_prefilled_placeholder = false;

  // Whether the |username_element| has an autocomplete=username attribute. This
  // is only used in parsed HTML forms.
  bool username_marked_by_site = false;

  // The username. Optional.
  //
  // When parsing an HTML form, this is typically empty unless the site
  // has implemented some form of autofill.
  base::string16 username_value;

  // This member is populated in cases where we there are multiple input
  // elements that could possibly be the username. Used when our heuristics for
  // determining the username are incorrect. Optional.
  ValueElementVector all_possible_usernames;

  // This member is populated in cases where we there are multiple possible
  // password values. Used in pending password state, to populate a dropdown
  // for possible passwords. Contains all possible passwords. Optional.
  ValueElementVector all_possible_passwords;

  // True if |all_possible_passwords| have autofilled value or its part.
  bool form_has_autofilled_value = false;

  // The name of the input element corresponding to the current password.
  // Optional (improves scoring).
  //
  // When parsing an HTML form, this will always be set, unless it is a sign-up
  // form or a change password form that does not ask for the current password.
  // In these two cases the |new_password_element| will always be set.
  base::string16 password_element;

  // The renderer id of the password input element. It is set during the new
  // form parsing and not persisted.
  uint32_t password_element_renderer_id =
      FormFieldData::kNotSetFormControlRendererId;

  // The current password. Must be non-empty for PasswordForm instances that are
  // meant to be persisted to the password store.
  //
  // When parsing an HTML form, this is typically empty.
  base::string16 password_value;

  // If the form was a sign-up or a change password form, the name of the input
  // element corresponding to the new password. Optional, and not persisted.
  base::string16 new_password_element;

  // The renderer id of the new password input element. It is set during the new
  // form parsing and not persisted.
  uint32_t new_password_element_renderer_id =
      FormFieldData::kNotSetFormControlRendererId;

  // The confirmation password element. Optional, only set on form parsing, and
  // not persisted.
  base::string16 confirmation_password_element;

  // The renderer id of the confirmation password input element. It is set
  // during the new form parsing and not persisted.
  uint32_t confirmation_password_element_renderer_id =
      FormFieldData::kNotSetFormControlRendererId;

  // The new password. Optional, and not persisted.
  base::string16 new_password_value;

  // Whether the |new_password_element| has an autocomplete=new-password
  // attribute. This is only used in parsed HTML forms.
  bool new_password_marked_by_site = false;

  // True if this PasswordForm represents the last username/password login the
  // user selected to log in to the site. If there is only one saved entry for
  // the site, this will always be true, but when there are multiple entries
  // the PasswordManager ensures that only one of them has a preferred bit set
  // to true. Default to false.
  //
  // When parsing an HTML form, this is not used.
  bool preferred = false;

  // When the login was saved (by chrome).
  //
  // When parsing an HTML form, this is not used.
  base::Time date_created;

  // When the login was downloaded from the sync server. For local passwords is
  // not used.
  //
  // When parsing an HTML form, this is not used.
  base::Time date_synced;

  // Tracks if the user opted to never remember passwords for this form. Default
  // to false.
  //
  // When parsing an HTML form, this is not used.
  bool blacklisted_by_user = false;

  // The form type.
  Type type = Type::kManual;

  // The number of times that this username/password has been used to
  // authenticate the user.
  //
  // When parsing an HTML form, this is not used.
  int times_used = 0;

  // Autofill representation of this form. Used to communicate with the
  // Autofill servers if necessary. Currently this is only used to help
  // determine forms where we can trigger password generation.
  //
  // When parsing an HTML form, this is normally set.
  FormData form_data;

  // What information has been sent to the Autofill server about this form.
  GenerationUploadStatus generation_upload_status =
      GenerationUploadStatus::kNoSignalSent;

  // These following fields are set by a website using the Credential Manager
  // API. They will be empty and remain unused for sites which do not use that
  // API.
  //
  // User friendly name to show in the UI.
  base::string16 display_name;

  // The URL of this credential's icon, such as the user's avatar, to display
  // in the UI.
  // TODO(msramek): This field was previously named |avatar_url|. It is still
  // named this way in the password store backends (e.g. the avatar_url column
  // in the SQL DB of LoginDatabase) and for the purposes of syncing
  // (i.e in PasswordSpecificsData). Rename these occurrences.
  GURL icon_url;

  // The origin of identity provider used for federated login.
  url::Origin federation_origin;

  // If true, Chrome will not return this credential to a site in response to
  // 'navigator.credentials.request()' without user interaction.
  // Once user selects this credential the flag is reseted.
  bool skip_zero_click = false;

  // If true, this form was parsed using Autofill predictions.
  bool was_parsed_using_autofill_predictions = false;

  // If true, this match was found using public suffix matching.
  bool is_public_suffix_match = false;

  // If true, this is a credential saved through an Android application, and
  // found using affiliation-based match.
  bool is_affiliation_based_match = false;

  // The type of the event that was taken as an indication that this form is
  // being or has already been submitted. This field is not persisted and filled
  // out only for submitted forms.
  mojom::SubmissionIndicatorEvent submission_event =
      mojom::SubmissionIndicatorEvent::NONE;

  // True iff heuristics declined this form for normal saving or filling (e.g.
  // only credit card fields were found). But this form can be saved or filled
  // only with the fallback.
  bool only_for_fallback = false;

  // True iff the new password field was found with server hints or autocomplete
  // attributes. Only set on form parsing for filling, and not persisted. Used
  // as signal for password generation eligibility.
  bool is_new_password_reliable = false;

  // Return true if we consider this form to be a change password form.
  // We use only client heuristics, so it could include signup forms.
  bool IsPossibleChangePasswordForm() const;

  // Return true if we consider this form to be a change password form
  // without username field. We use only client heuristics, so it could
  // include signup forms.
  bool IsPossibleChangePasswordFormWithoutUsername() const;

  // Returns true if current password element is set.
  bool HasPasswordElement() const;

  // True iff |federation_origin| isn't empty.
  bool IsFederatedCredential() const;

  // Equality operators for testing.
  bool operator==(const PasswordForm& form) const;
  bool operator!=(const PasswordForm& form) const;

  PasswordForm();
  PasswordForm(const PasswordForm& other);
  PasswordForm(PasswordForm&& other);
  ~PasswordForm();

  PasswordForm& operator=(const PasswordForm& form);
  PasswordForm& operator=(PasswordForm&& form);
};

// True if the unique keys for the forms are the same. The unique key is
// (origin, username_element, username_value, password_element, signon_realm).
bool ArePasswordFormUniqueKeysEqual(const PasswordForm& left,
                                    const PasswordForm& right);

// A comparator for the unique key.
struct LessThanUniqueKey {
  bool operator()(const std::unique_ptr<PasswordForm>& left,
                  const std::unique_ptr<PasswordForm>& right) const;
};

// Converts a vector of ValueElementPair to string.
base::string16 ValueElementVectorToString(
    const ValueElementVector& value_element_pairs);

// Returns true if |scheme| corresponds to http auth scheme.
bool IsHttpAuthScheme(PasswordForm::Scheme scheme);

// For testing.
std::ostream& operator<<(std::ostream& os, const PasswordForm& form);
std::ostream& operator<<(std::ostream& os, PasswordForm* form);

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_COMMON_PASSWORD_FORM_H__
