Commit e70ed1c3 authored by Mohamed Amir Yosef's avatar Mohamed Amir Yosef Committed by Commit Bot

[Passwords] Fix for LoginDatabase that got downgraded from 25 to 24

The fix to protect against login database downgrade has been included
in version Chrome 78. However, users running Chrome 77 still suffer
from this issue and could potentially download the login database
from version 25 to 24 without changing the schema.
Chrome 25 however introduce a new column in the login database.
Therefore, trying to migrate again from version 25 to 24 would actually
fail and results in password manager to stop working.

Before this patch:
If users enter this broken stay, they will stay there indefinitely.

After this patch:
The code would auto-correct the version for such broken state.

The issue has been reported in the public support forums.
Details are in the linked bug.

This CL in addition adds the proper testing for this user flow.

Bug: 1020320
Change-Id: Ib97e26a21ba4840f599e599edc75835292584873
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899462Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712589}
parent c1c3152a
...@@ -469,6 +469,7 @@ bundle_data("unit_tests_bundle_data") { ...@@ -469,6 +469,7 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/password_manager/login_db_v22.sql", "//components/test/data/password_manager/login_db_v22.sql",
"//components/test/data/password_manager/login_db_v23.sql", "//components/test/data/password_manager/login_db_v23.sql",
"//components/test/data/password_manager/login_db_v24.sql", "//components/test/data/password_manager/login_db_v24.sql",
"//components/test/data/password_manager/login_db_v24_broken.sql",
"//components/test/data/password_manager/login_db_v25.sql", "//components/test/data/password_manager/login_db_v25.sql",
"//components/test/data/password_manager/login_db_v26.sql", "//components/test/data/password_manager/login_db_v26.sql",
"//components/test/data/password_manager/login_db_v2_broken.sql", "//components/test/data/password_manager/login_db_v2_broken.sql",
......
...@@ -655,6 +655,13 @@ bool FixVersionIfNeeded(sql::Database* db, int* current_version) { ...@@ -655,6 +655,13 @@ bool FixVersionIfNeeded(sql::Database* db, int* current_version) {
if (db->DoesColumnExist("logins", "form_data")) if (db->DoesColumnExist("logins", "form_data"))
*current_version = 4; *current_version = 4;
} }
// "date_last_used" columns has been introduced in version 25. if it exists,
// the version should be at least 25. This has been added to address this bug
// (crbug.com/1020320).
if (*current_version < 25) {
if (db->DoesColumnExist("logins", "date_last_used"))
*current_version = 25;
}
return true; return true;
} }
......
...@@ -2304,7 +2304,7 @@ INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent, ...@@ -2304,7 +2304,7 @@ INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
testing::Values(9)); testing::Values(9));
INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent, INSTANTIATE_TEST_SUITE_P(MigrationToVCurrent,
LoginDatabaseMigrationTestBroken, LoginDatabaseMigrationTestBroken,
testing::Range(1, 4)); testing::Values(1, 2, 3, 24));
class LoginDatabaseUndecryptableLoginsTest : public testing::Test { class LoginDatabaseUndecryptableLoginsTest : public testing::Test {
protected: protected:
......
-- Version 25 schema with meta.version==24. Tests http://crbug.com/1020320
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
INSERT INTO "meta" VALUES('last_compatible_version','19');
INSERT INTO "meta" VALUES('version','24');
CREATE TABLE logins (
origin_url VARCHAR NOT NULL,
action_url VARCHAR,
username_element VARCHAR,
username_value VARCHAR,
password_element VARCHAR,
password_value BLOB,
submit_element VARCHAR,
signon_realm VARCHAR NOT NULL,
preferred INTEGER NOT NULL,
date_created INTEGER NOT NULL,
blacklisted_by_user INTEGER NOT NULL,
scheme INTEGER NOT NULL,
password_type INTEGER,
times_used INTEGER,
form_data BLOB,
date_synced INTEGER,
display_name VARCHAR,
icon_url VARCHAR,
federation_url VARCHAR,
skip_zero_click INTEGER,
generation_upload_status INTEGER,
possible_username_pairs BLOB,
id INTEGER,
date_last_used INTEGER,
UNIQUE (origin_url, username_element, username_value, password_element, signon_realm),
PRIMARY KEY (id));
INSERT INTO "logins" (origin_url,action_url,username_element,username_value,password_element,password_value,submit_element,signon_realm,preferred,date_created,blacklisted_by_user,scheme,password_type,times_used,form_data,date_synced,display_name,icon_url,federation_url,skip_zero_click,generation_upload_status,possible_username_pairs,date_last_used) VALUES(
'https://accounts.google.com/ServiceLogin', /* origin_url */
'https://accounts.google.com/ServiceLoginAuth', /* action_url */
'Email', /* username_element */
'theerikchen', /* username_value */
'Passwd', /* password_element */
X'', /* password_value */
'', /* submit_element */
'https://accounts.google.com/', /* signon_realm */
1, /* preferred */
13047429345000000, /* date_created */
0, /* blacklisted_by_user */
0, /* scheme */
0, /* password_type */
1, /* times_used */
X'18000000020000000000000000000000000000000000000000000000', /* form_data */
0, /* date_synced */
'', /* display_name */
'', /* icon_url */
'', /* federation_url */
1, /* skip_zero_click */
0, /* generation_upload_status */
X'00000000', /* possible_username_pairs */
0 /* date_last_used */
);
INSERT INTO "logins" (origin_url,action_url,username_element,username_value,password_element,password_value,submit_element,signon_realm,preferred,date_created,blacklisted_by_user,scheme,password_type,times_used,form_data,date_synced,display_name,icon_url,federation_url,skip_zero_click,generation_upload_status,possible_username_pairs,date_last_used) VALUES(
'https://accounts.google.com/ServiceLogin', /* origin_url */
'https://accounts.google.com/ServiceLoginAuth', /* action_url */
'Email', /* username_element */
'theerikchen2', /* username_value */
'Passwd', /* password_element */
X'', /* password_value */
'non-empty', /* submit_element */
'https://accounts.google.com/', /* signon_realm */
1, /* preferred */
13047423600000000, /* date_created */
0, /* blacklisted_by_user */
0, /* scheme */
0, /* password_type */
1, /* times_used */
X'18000000020000000000000000000000000000000000000000000000', /* form_data */
0, /* date_synced */
'', /* display_name */
'https://www.google.com/icon', /* icon_url */
'', /* federation_url */
1, /* skip_zero_click */
0, /* generation_upload_status */
X'00000000', /* possible_username_pairs */
0 /* date_last_used */
);
INSERT INTO "logins" (origin_url,action_url,username_element,username_value,password_element,password_value,submit_element,signon_realm,preferred,date_created,blacklisted_by_user,scheme,password_type,times_used,form_data,date_synced,display_name,icon_url,federation_url,skip_zero_click,generation_upload_status,possible_username_pairs,date_last_used) VALUES(
'http://example.com', /* origin_url */
'http://example.com/landing', /* action_url */
'', /* username_element */
'user', /* username_value */
'', /* password_element */
X'', /* password_value */
'non-empty', /* submit_element */
'http://example.com', /* signon_realm */
1, /* preferred */
13047423600000000, /* date_created */
0, /* blacklisted_by_user */
1, /* scheme */
0, /* password_type */
1, /* times_used */
X'18000000020000000000000000000000000000000000000000000000', /* form_data */
0, /* date_synced */
'', /* display_name */
'https://www.google.com/icon', /* icon_url */
'', /* federation_url */
1, /* skip_zero_click */
0, /* generation_upload_status */
X'00000000', /* possible_username_pairs */
0 /* date_last_used */
);
CREATE INDEX logins_signon ON logins (signon_realm);
CREATE TABLE stats (
origin_domain VARCHAR NOT NULL,
username_value VARCHAR,
dismissal_count INTEGER,
update_time INTEGER NOT NULL,
UNIQUE(origin_domain, username_value));
CREATE INDEX stats_origin ON stats(origin_domain);
CREATE TABLE sync_entities_metadata (
storage_key INTEGER,
metadata VARCHAR NOT NULL,
PRIMARY KEY (storage_key)
);
CREATE TABLE sync_model_metadata (
id INTEGER,
metadata VARCHAR NOT NULL,
PRIMARY KEY (id)
);
COMMIT;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment