// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Sync protocol datatype extension for password data.
// If you change or add any fields in this file, update proto_visitors.h and
// potentially proto_enum_conversions.{h, cc}.
syntax = "proto2";
option java_multiple_files = true;
option java_package = "org.chromium.components.sync.protocol";
option optimize_for = LITE_RUNTIME;
package sync_pb;
import "components/sync/protocol/encryption.proto";
// These are the properties that get serialized into the |encrypted| field of
// PasswordSpecifics. They correspond to fields in
// password_manager::PasswordForm.
//
// Sync unique tag is calculated as
// EscapePath(origin) + "|" +
// EscapePath(username_element) + "|" +
// EscapePath(username_value) + "|" +
// EscapePath(password_element) + "|" +
// EscapePath(signon_realm)
// where '+' is the string concatenation operation. EscapePath escapes a partial
// or complete file/pathname. This includes non-printable, non-7bit, and
// (including space) the following characters ' "#%:<>?[\]^`{|}'. The space
// character is encoded as '%20'.
// A simple example of PasswordSpecificsData, as created by Chrome for a web
// form that the user submitted. E.g. federated credentials or credentials for
// Android apps may have different fields set.
// PasswordSpecificsData {
// action: "https://example.com/",
// avatar_url: "",
// blacklisted: false,
// date_created: 13305119271948046,
// date_last_used: 13305119270102691,
// date_password_modified_windows_epoch_micros: 13305119271949070,
// display_name: "",
// federation_url: "",
// notes: {},
// origin: "https://rsolomakhin.github.io/autofill/",
// password_element: "password",
// password_issues: {},
// password_value: "pwd",
// scheme: 0,
// signon_realm: "https://rsolomakhin.github.io/",
// times_used: 0,
// type: 0,
// username_element: "username",
// username_value: "Superman"
// }
// All the strings are encoded with UTF-8. URLs are encoded in Punycode.
message PasswordIssues {
message PasswordIssue {
// Timestamp set by a client detecting the issue for the first time.
// Number of microseconds since Windows epoch (1601).
// This can be unset even if is_muted is set in a few cases in
// storage (for a time mutes were written without setting this
// field - fixed starting 2021-11-10).
optional uint64 date_first_detection_windows_epoch_micros = 1;
// Whether the issue was muted by user.
optional bool is_muted = 2;
// Whether the backend should notify the user about this issue.
// Set to true if the user hasn't already seen a client notification for
// this issue (e.g. a leak detection prompt in Chrome). The backend sending
// notifications does not reset this field. All other sources can write this
// in both `PasswordSpecificsData` and `PasswordSpecificsMetadata` and do
// so.
optional bool trigger_notification_from_backend_on_detection = 3;
}
optional PasswordIssue leaked_password_issue = 1;
optional PasswordIssue reused_password_issue = 2;
optional PasswordIssue weak_password_issue = 3;
optional PasswordIssue phished_password_issue = 4;
}
message PasswordSpecificsData {
// The different types of the saved credential.
enum Scheme {
// SCHEME_HTML, the credential represents either a parsed HTML form, or an
// android credential or a password saved through Credential Management API
// (https://w3c.github.io/webappsec/specs/credentialmanagement/).
SCHEME_HTML = 0;
// SCHEME_BASIC, basic access http authentication.
SCHEME_BASIC = 1;
// SCHEME_DIGEST, digest access authentication.
SCHEME_DIGEST = 2;
// SCHEME_OTHER, another proxy access authentication.
SCHEME_OTHER = 3;
// USERNAME_ONLY, partial credentials saved on Android that contain only
// username and miss the password.
USERNAME_ONLY = 4;
}
// See the enum above.
optional int32 scheme = 1;
// Signon realm stores information on where the saved password was stored, and
// where it's supposed to be filled again.
//
// It can take various formats depending on the exact circumstances where it
// was recorded. Note that the format is *not* guaranteed to be a valid URL or
// URI:
//
// * For parsed web forms and normal passwords saved through Credential
// Manager
// API: <http-scheme>://<url-host>[:<url-port>]/
//
// where
// <http-scheme> is one of "http" or "https"
// <url-host> is the host for which the password was stored
// <url-port> is the option port on the host
// The signon realm is a valid URL in this case with an empty path.
// Examples:
// http://www.example.com/
// https://127.0.0.1/
// http://www.google.com:8080/
// http://192.168.1.254/
// https://accounts.google.com/
//
// * For Android apps saved through Autofill with Google:
// android://<hash-of-cert>@<package-name>/
// where
// <hash-of-cert> is the base64 encoded SHA512 of the app's public
// certificate <package-name> is the app's package name
// Examples:
// android://kCyQDzpaoAX2gs-1zdGPKNAeICb8LzRFOxa4NCq0jO8c8d_NFS_q-Y35bU3Nq3GmFV2lLurmNvIZa6YPYZwmWg==@com.pinterest/
// android://mNUCvTnoWBkzIhSSkVj-uzAdK42YagmCmyUtPoC6JPmYAN3wKpmTdIRsdJtz6pzNBye8XL7nBbEcx-y9CJeo9A==@com.twitter.android.lite/
//
// * For federated credentials:
// federation://<origin_host>/<federation_host>
// where
// <origin_host> is the host for which the login information was stored
// <federation_host> is the host of the federation provider that was
// used to sign in
// Examples:
// federation://www.example.com/accounts.google.com
// federation://uk.trustpilot.com/www.facebook.com
//
// * For proxy auth:
// <proxy-host>[:<proxy_port>]/<auth-realm>
// where
// <proxy-host> is the host of the proxy for which the password was
// stored
// <proxy-port> is the port of the proxy
// <auth-realm> is a string provided by the proxy during authentication.
// It can contain spaces.
// Examples:
// proxy2.eq.edu.au:80/MISldap
// proxy.det.nsw.edu.au:8080/NSW Department of Education
// 10.47.2.250:3128/Squid Proxy Server CPUT
// default.go2https.com:443/(******Get password from vpnso.com/account/
// *****)
//
// * For HTTP basic auth:
// <http-scheme>://<url-host>[:<url-port>]/<auth-realm>
// where
// <http-scheme> is one of "http" or "https"
// <url-host> is the host for which the password was stored
// <url-port> is the option port on the host
// <auth-realm> is a string provided by the host during authentication.
// It can contain spaces.
// Examples:
// http://192.168.1.1/Broadband Router
// http://192.168.0.1/TP-LINK Wireless N Router WR841N
// http://192.168.1.1/index.htm
// https://www.edge.asic.gov.au/ASIC eBusiness
optional string signon_realm = 2;
// For parsed web forms and Credential Management API:
// url-scheme://url-host[:url-port]/path
// For Android: "android://<hash of cert>@<package name>/"
// For proxy/HTTP auth: url-scheme://url-host[:url-port]/path
optional string origin = 3;
// Only for web-parsed forms - the action target of the form:
// url-scheme://url-host[:url-port]/path
optional string action = 4;
// Only for web-parsed forms - the name of the element containing username.
optional string username_element = 5;
// For all: the username.
// For blacklisted forms: <empty>.
optional string username_value = 6;
// Only for web-parsed forms - the name of the element containing password.
optional string password_element = 7;
// For all: the password.
// For federated logins and blacklisted forms: <empty>
optional string password_value = 8;
// Deprecated: http://crbug.com/413020
// True if the credential was saved for a HTTPS session with a valid SSL cert.
// Ignored for Android apps.
optional bool ssl_valid = 9 [deprecated = true];
// True for the last credential used for logging in on a given site.
// Deprecated in M81.
optional bool preferred = 10 [deprecated = true];
// Time when the credential was created. Amount of microseconds since 1601.
optional int64 date_created = 11;
// True, if user chose permanently not to save the credentials for the form.
optional bool blacklisted = 12;
// kFormSubmission(0), user manually filled the username and the password
// in the form.
// kGenerated(1), the credential was auto generated.
// kApi(2), the credential was generated from Credential Management API.
// kManuallyAdded(3), user manually created the password credential
// via Settings.
// kImported(4), the credential was imported using the import flow.
// kReceivedViaSharing(5), the credential has been received via the password
// sharing feature.
optional int32 type = 13;
// Number of times this login was used for logging in using an HTML form.
// Chrome uses this field to distinguish log-in and sign-up forms.
optional int32 times_used = 14;
// A human readable name of the account holder. Set by CredentialManager API
// and Android.
optional string display_name = 15;
// A URL of the avatar for the credential. Set by CredentialManager API and
// Android.
optional string avatar_url = 16;
// A URL of the IdP used to verify the credential. Set by Credential Manager
// API and Android.
optional string federation_url = 17;
// Time when the credential was last used. This covers *successful* logins to
// the website, and explicit updates to the password. It does *not* cover if
// the password just gets filled but not actually submitted, or if the login
// failed.
// Note that password consumers other than Chrome (e.g. Google Play Services)
// might not update this at all.
// Amount of microseconds since 1601, aka Windows epoch.
optional int64 date_last_used = 18;
// Set if an issue was detected that puts this password at risk. All the
// clients are expected to clear the field when the password value is updated.
// 'reused' part can be additionally reset when the analysis on the entire
// password store is completed.
optional PasswordIssues password_issues = 19;
// Time when the |password_value| was last modified. For new credentials it
// should be set to |date_created|. For subsequent updates the timestamp is
// changed if and only if the new password value was saved.
// Number of microseconds since Windows epoch (1601).
optional int64 date_password_modified_windows_epoch_micros = 20;
message Notes {
message Note {
// The display name must be unique within the scope of a password.
optional string unique_display_name = 1;
// The user-defined value of the note.
optional string value = 2;
// The creation time of the note. Number of microseconds since 1601.
optional int64 date_created_windows_epoch_micros = 3;
// Whether the value of the note is not displayed in plain text by
// default.
optional bool hide_by_default = 4;
}
repeated Note note = 1;
}
reserved 21;
// Set of extra notes that the user attached to the password. The presence of
// this field, even with an empty Notes message, becomes the authoritative
// value for notes and would disregard whatever `encrypted_notes_backup`
// contains.
optional Notes notes = 22;
// For credentials that have been shared by another user, this field captures
// the sender email. It's empty for credentials that weren't received via
// password sharing feature.
optional string sender_email = 23;
// Similar to `sender_email` but for the sender name.
optional string sender_name = 24;
// The timestamp when the password was received via sharing feature from
// another user.
optional int64 date_received_windows_epoch_micros = 25;
// Whether the user has been already notified that they received this password
// from another user via the password sharing feature. This is synced to avoid
// showing the notification on multiple devices.
optional bool sharing_notification_displayed = 26;
// Similar to `sender_email` but for the url of the sender profile image.
optional string sender_profile_image_url = 27;
}
// Contains the password specifics metadata which simplifies its lookup.
message PasswordSpecificsMetadata {
// The signon realm for the credential. For more details, see the
// `signon_realm` field in PasswordSpecificsData.
optional string url = 1;
// True, if user chose permanently not to save the credentials for the form.
// Introduced in M82. Copy from PasswordSpecificsData.blacklisted.
optional bool blacklisted = 2;
// Copy from PasswordSpecificsData.date_last_used.
// Introduced in M112.
optional int64 date_last_used_windows_epoch_micros = 3;
// Copy from PasswordSpecificsData.password_issues. Introduced in M114.
optional PasswordIssues password_issues = 4;
// Copy from PasswordSpecificsData.type. Introduced in M119.
optional int32 type = 13;
}
// Properties of password sync objects.
message PasswordSpecifics {
// The actual password data. Contains an encrypted PasswordSpecificsData
// message.
optional EncryptedData encrypted = 1;
// An unsynced field for use internally on the client. This field should
// never be set in any network-based communications because it contains
// unencrypted material.
optional PasswordSpecificsData client_only_encrypted_data = 2;
// Password related metadata, which is sent to the server side. The field
// should never be set for full encryption users. If encryption is enabled,
// this field must be cleared.
optional PasswordSpecificsMetadata unencrypted_metadata = 3;
reserved 4;
// An encrypted backup of the notes field inside the PasswordSpecificsData.
// The Sync server preserves the contents of this field across commits from
// legacy clients that don't set this field. It is the responsibility of Sync
// clients to populate the contents of PasswordSpecificsData notes fields
// using the contents of this field. This should be deprecated together with
// the logic for preserving it on the server when clients without support for
// the |notes| field are no longer allowed by the server (below support
// version horizon).
//
// Encryption key considerations:
// a) For commits, the client must use the same key for both encrypted blobs.
// b) For handling getupdates, the two keys may NOT necessarily match the
// encryption key used, as in theory the new blob could be "behind" if key
// rotation took place. As of today, it is safe to assume that if
// |encrypted| is decryptable by a client, then |encrypted_notes_backup|
// must be decryptable too (i.e. the Nigori keybag should include older
// versions of the key). But not the other way round.
//
// If both `encrypted_notes_backup` and the `notes` in `encrypted` are
// populated, the one in notes is considered the authoritative value.
optional EncryptedData encrypted_notes_backup = 5;
}