Commit 1d26103f authored by vasilii@chromium.org's avatar vasilii@chromium.org

Support to remove passwords by date_synced timestamp.

The new method RemoveLoginsSyncedBetween() works exactly like the existing RemoveLoginsCreatedBetween(). 

BUG=362679
TBR=zea@chromium.org

Review URL: https://codereview.chromium.org/335893002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277863 0039d316-1c4b-4281-b951-d872f2087c98
parent 99b73c36
...@@ -642,26 +642,17 @@ bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) { ...@@ -642,26 +642,17 @@ bool NativeBackendGnome::RemoveLogin(const PasswordForm& form) {
return true; return true;
} }
bool NativeBackendGnome::RemoveLoginsCreatedBetween( bool NativeBackendGnome::RemoveLoginsCreatedBetween(base::Time delete_begin,
const base::Time& delete_begin, base::Time delete_end) {
const base::Time& delete_end) { return RemoveLoginsBetween(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); delete_begin, delete_end, CREATION_TIMESTAMP, NULL);
bool ok = true; }
// We could walk the list and delete items as we find them, but it is much
// easier to build the list and use RemoveLogin() to delete them.
PasswordFormList forms;
if (!GetAllLogins(&forms))
return false;
for (size_t i = 0; i < forms.size(); ++i) { bool NativeBackendGnome::RemoveLoginsSyncedBetween(
if (delete_begin <= forms[i]->date_created && base::Time delete_begin,
(delete_end.is_null() || forms[i]->date_created < delete_end)) { base::Time delete_end,
if (!RemoveLogin(*forms[i])) password_manager::PasswordStoreChangeList* changes) {
ok = false; return RemoveLoginsBetween(delete_begin, delete_end, SYNC_TIMESTAMP, changes);
}
delete forms[i];
}
return ok;
} }
bool NativeBackendGnome::GetLogins(const PasswordForm& form, bool NativeBackendGnome::GetLogins(const PasswordForm& form,
...@@ -683,27 +674,10 @@ bool NativeBackendGnome::GetLogins(const PasswordForm& form, ...@@ -683,27 +674,10 @@ bool NativeBackendGnome::GetLogins(const PasswordForm& form,
return true; return true;
} }
bool NativeBackendGnome::GetLoginsCreatedBetween(const base::Time& get_begin, bool NativeBackendGnome::GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) { PasswordFormList* forms) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); return GetLoginsBetween(get_begin, get_end, CREATION_TIMESTAMP, forms);
// We could walk the list and add items as we find them, but it is much
// easier to build the list and then filter the results.
PasswordFormList all_forms;
if (!GetAllLogins(&all_forms))
return false;
forms->reserve(forms->size() + all_forms.size());
for (size_t i = 0; i < all_forms.size(); ++i) {
if (get_begin <= all_forms[i]->date_created &&
(get_end.is_null() || all_forms[i]->date_created < get_end)) {
forms->push_back(all_forms[i]);
} else {
delete all_forms[i];
}
}
return true;
} }
bool NativeBackendGnome::GetAutofillableLogins(PasswordFormList* forms) { bool NativeBackendGnome::GetAutofillableLogins(PasswordFormList* forms) {
...@@ -753,6 +727,61 @@ bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) { ...@@ -753,6 +727,61 @@ bool NativeBackendGnome::GetAllLogins(PasswordFormList* forms) {
return true; return true;
} }
bool NativeBackendGnome::GetLoginsBetween(base::Time get_begin,
base::Time get_end,
TimestampToCompare date_to_compare,
PasswordFormList* forms) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
// We could walk the list and add items as we find them, but it is much
// easier to build the list and then filter the results.
PasswordFormList all_forms;
if (!GetAllLogins(&all_forms))
return false;
base::Time autofill::PasswordForm::*date_member =
date_to_compare == CREATION_TIMESTAMP
? &autofill::PasswordForm::date_created
: &autofill::PasswordForm::date_synced;
for (size_t i = 0; i < all_forms.size(); ++i) {
if (get_begin <= all_forms[i]->*date_member &&
(get_end.is_null() || all_forms[i]->*date_member < get_end)) {
forms->push_back(all_forms[i]);
} else {
delete all_forms[i];
}
}
return true;
}
bool NativeBackendGnome::RemoveLoginsBetween(
base::Time get_begin,
base::Time get_end,
TimestampToCompare date_to_compare,
password_manager::PasswordStoreChangeList* changes) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
if (changes)
changes->clear();
// We could walk the list and delete items as we find them, but it is much
// easier to build the list and use RemoveLogin() to delete them.
ScopedVector<autofill::PasswordForm> forms;
if (!GetLoginsBetween(get_begin, get_end, date_to_compare, &forms.get()))
return false;
bool ok = true;
for (size_t i = 0; i < forms.size(); ++i) {
if (RemoveLogin(*forms[i])) {
if (changes) {
changes->push_back(password_manager::PasswordStoreChange(
password_manager::PasswordStoreChange::REMOVE, *forms[i]));
}
} else {
ok = false;
}
}
return ok;
}
std::string NativeBackendGnome::GetProfileSpecificAppString() const { std::string NativeBackendGnome::GetProfileSpecificAppString() const {
// Originally, the application string was always just "chrome" and used only // Originally, the application string was always just "chrome" and used only
// so that we had *something* to search for since GNOME Keyring won't search // so that we had *something* to search for since GNOME Keyring won't search
......
...@@ -87,17 +87,26 @@ class NativeBackendGnome : public PasswordStoreX::NativeBackend, ...@@ -87,17 +87,26 @@ class NativeBackendGnome : public PasswordStoreX::NativeBackend,
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
password_manager::PasswordStoreChangeList* changes) OVERRIDE; password_manager::PasswordStoreChangeList* changes) OVERRIDE;
virtual bool RemoveLogin(const autofill::PasswordForm& form) OVERRIDE; virtual bool RemoveLogin(const autofill::PasswordForm& form) OVERRIDE;
virtual bool RemoveLoginsCreatedBetween( virtual bool RemoveLoginsCreatedBetween(base::Time delete_begin,
const base::Time& delete_begin, const base::Time& delete_end) OVERRIDE; base::Time delete_end) OVERRIDE;
virtual bool RemoveLoginsSyncedBetween(
base::Time delete_begin,
base::Time delete_end,
password_manager::PasswordStoreChangeList* changes) OVERRIDE;
virtual bool GetLogins(const autofill::PasswordForm& form, virtual bool GetLogins(const autofill::PasswordForm& form,
PasswordFormList* forms) OVERRIDE; PasswordFormList* forms) OVERRIDE;
virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, virtual bool GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) OVERRIDE; PasswordFormList* forms) OVERRIDE;
virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE; virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE;
virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE; virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE;
private: private:
enum TimestampToCompare {
CREATION_TIMESTAMP,
SYNC_TIMESTAMP,
};
// Adds a login form without checking for one to replace first. // Adds a login form without checking for one to replace first.
bool RawAddLogin(const autofill::PasswordForm& form); bool RawAddLogin(const autofill::PasswordForm& form);
...@@ -107,6 +116,20 @@ class NativeBackendGnome : public PasswordStoreX::NativeBackend, ...@@ -107,6 +116,20 @@ class NativeBackendGnome : public PasswordStoreX::NativeBackend,
// Helper for GetLoginsCreatedBetween(). // Helper for GetLoginsCreatedBetween().
bool GetAllLogins(PasswordFormList* forms); bool GetAllLogins(PasswordFormList* forms);
// Retrieves password created/synced in the time interval. Returns |true| if
// the operation succeeded.
bool GetLoginsBetween(base::Time get_begin,
base::Time get_end,
TimestampToCompare date_to_compare,
PasswordFormList* forms);
// Removes password created/synced in the time interval. Returns |true| if the
// operation succeeded. |changes| will contain the changes applied.
bool RemoveLoginsBetween(base::Time get_begin,
base::Time get_end,
TimestampToCompare date_to_compare,
password_manager::PasswordStoreChangeList* changes);
// Generates a profile-specific app string based on profile_id_. // Generates a profile-specific app string based on profile_id_.
std::string GetProfileSpecificAppString() const; std::string GetProfileSpecificAppString() const;
......
...@@ -309,6 +309,13 @@ void CheckPasswordChanges(const PasswordStoreChangeList& expected_list, ...@@ -309,6 +309,13 @@ void CheckPasswordChanges(const PasswordStoreChangeList& expected_list,
} }
} }
void CheckPasswordChangesWithResult(const PasswordStoreChangeList* expected,
const PasswordStoreChangeList* actual,
bool result) {
EXPECT_TRUE(result);
CheckPasswordChanges(*expected, *actual);
}
} // anonymous namespace } // anonymous namespace
class NativeBackendGnomeTest : public testing::Test { class NativeBackendGnomeTest : public testing::Test {
...@@ -948,4 +955,65 @@ TEST_F(NativeBackendGnomeTest, ListLoginsAppends) { ...@@ -948,4 +955,65 @@ TEST_F(NativeBackendGnomeTest, ListLoginsAppends) {
CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
} }
TEST_F(NativeBackendGnomeTest, RemoveLoginsSyncedBetween) {
NativeBackendGnome backend(42);
backend.Init();
base::Time now = base::Time::Now();
base::Time next_day = now + base::TimeDelta::FromDays(1);
form_google_.date_synced = now;
form_isc_.date_synced = next_day;
form_google_.date_created = base::Time();
form_isc_.date_created = base::Time();
BrowserThread::PostTask(
BrowserThread::DB,
FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend),
form_google_));
BrowserThread::PostTask(
BrowserThread::DB,
FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
base::Unretained(&backend),
form_isc_));
PasswordStoreChangeList expected_changes;
expected_changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
PasswordStoreChangeList changes;
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::DB,
FROM_HERE,
base::Bind(&NativeBackendGnome::RemoveLoginsSyncedBetween,
base::Unretained(&backend),
base::Time(),
next_day,
&changes),
base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
RunBothThreads();
EXPECT_EQ(1u, mock_keyring_items.size());
if (mock_keyring_items.size() > 0)
CheckMockKeyringItem(&mock_keyring_items[0], form_isc_, "chrome-42");
// Remove form_isc_.
expected_changes.clear();
expected_changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, form_isc_));
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::DB,
FROM_HERE,
base::Bind(&NativeBackendGnome::RemoveLoginsSyncedBetween,
base::Unretained(&backend),
next_day,
base::Time(),
&changes),
base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
RunBothThreads();
EXPECT_EQ(0u, mock_keyring_items.size());
}
// TODO(mdm): add more basic tests here at some point. // TODO(mdm): add more basic tests here at some point.
...@@ -46,12 +46,16 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend { ...@@ -46,12 +46,16 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend {
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
password_manager::PasswordStoreChangeList* changes) OVERRIDE; password_manager::PasswordStoreChangeList* changes) OVERRIDE;
virtual bool RemoveLogin(const autofill::PasswordForm& form) OVERRIDE; virtual bool RemoveLogin(const autofill::PasswordForm& form) OVERRIDE;
virtual bool RemoveLoginsCreatedBetween( virtual bool RemoveLoginsCreatedBetween(base::Time delete_begin,
const base::Time& delete_begin, const base::Time& delete_end) OVERRIDE; base::Time delete_end) OVERRIDE;
virtual bool RemoveLoginsSyncedBetween(
base::Time delete_begin,
base::Time delete_end,
password_manager::PasswordStoreChangeList* changes) OVERRIDE;
virtual bool GetLogins(const autofill::PasswordForm& form, virtual bool GetLogins(const autofill::PasswordForm& form,
PasswordFormList* forms) OVERRIDE; PasswordFormList* forms) OVERRIDE;
virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, virtual bool GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) OVERRIDE; PasswordFormList* forms) OVERRIDE;
virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE; virtual bool GetAutofillableLogins(PasswordFormList* forms) OVERRIDE;
virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE; virtual bool GetBlacklistLogins(PasswordFormList* forms) OVERRIDE;
...@@ -75,6 +79,11 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend { ...@@ -75,6 +79,11 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend {
PERMANENT_FAIL // Init failed, and is not likely to work later either. PERMANENT_FAIL // Init failed, and is not likely to work later either.
}; };
enum TimestampToCompare {
CREATION_TIMESTAMP,
SYNC_TIMESTAMP,
};
// Initialization. // Initialization.
bool StartKWalletd(); bool StartKWalletd();
InitResult InitWallet(); InitResult InitWallet();
...@@ -92,11 +101,12 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend { ...@@ -92,11 +101,12 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend {
bool autofillable, bool autofillable,
int wallet_handle); int wallet_handle);
// Reads PasswordForms from the wallet created in the given time range. // Reads PasswordForms from the wallet created/synced in the given time range.
bool GetLoginsList(PasswordFormList* forms, bool GetLoginsList(PasswordFormList* forms,
const base::Time& begin, const base::Time& begin,
const base::Time& end, const base::Time& end,
int wallet_handle); int wallet_handle,
TimestampToCompare date_to_compare);
// Helper for some of the above GetLoginsList() methods. // Helper for some of the above GetLoginsList() methods.
bool GetAllLogins(PasswordFormList* forms, int wallet_handle); bool GetAllLogins(PasswordFormList* forms, int wallet_handle);
...@@ -108,6 +118,13 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend { ...@@ -108,6 +118,13 @@ class NativeBackendKWallet : public PasswordStoreX::NativeBackend {
const std::string& signon_realm, const std::string& signon_realm,
int wallet_handle); int wallet_handle);
// Removes password created/synced in the time interval. Returns |true| if the
// operation succeeded. |changes| will contain the changes applied.
bool RemoveLoginsBetween(base::Time delete_begin,
base::Time delete_end,
TimestampToCompare date_to_compare,
password_manager::PasswordStoreChangeList* changes);
// Opens the wallet and ensures that the "Chrome Form Data" folder exists. // Opens the wallet and ensures that the "Chrome Form Data" folder exists.
// Returns kInvalidWalletHandle on error. // Returns kInvalidWalletHandle on error.
int WalletHandle(); int WalletHandle();
......
...@@ -171,12 +171,17 @@ class NativeBackendKWalletTestBase : public testing::Test { ...@@ -171,12 +171,17 @@ class NativeBackendKWalletTestBase : public testing::Test {
const PasswordForm& actual); const PasswordForm& actual);
static void CheckPasswordChanges(const PasswordStoreChangeList& expected, static void CheckPasswordChanges(const PasswordStoreChangeList& expected,
const PasswordStoreChangeList& actual); const PasswordStoreChangeList& actual);
static void CheckPasswordChangesWithResult(
const PasswordStoreChangeList* expected,
const PasswordStoreChangeList* actual,
bool result);
PasswordForm old_form_google_; PasswordForm old_form_google_;
PasswordForm form_google_; PasswordForm form_google_;
PasswordForm form_isc_; PasswordForm form_isc_;
}; };
// static
void NativeBackendKWalletTestBase::CheckPasswordForm( void NativeBackendKWalletTestBase::CheckPasswordForm(
const PasswordForm& expected, const PasswordForm& actual) { const PasswordForm& expected, const PasswordForm& actual) {
EXPECT_EQ(expected.origin, actual.origin); EXPECT_EQ(expected.origin, actual.origin);
...@@ -197,6 +202,7 @@ void NativeBackendKWalletTestBase::CheckPasswordForm( ...@@ -197,6 +202,7 @@ void NativeBackendKWalletTestBase::CheckPasswordForm(
EXPECT_EQ(expected.date_synced, actual.date_synced); EXPECT_EQ(expected.date_synced, actual.date_synced);
} }
// static
void NativeBackendKWalletTestBase::CheckPasswordChanges( void NativeBackendKWalletTestBase::CheckPasswordChanges(
const PasswordStoreChangeList& expected, const PasswordStoreChangeList& expected,
const PasswordStoreChangeList& actual) { const PasswordStoreChangeList& actual) {
...@@ -207,6 +213,15 @@ void NativeBackendKWalletTestBase::CheckPasswordChanges( ...@@ -207,6 +213,15 @@ void NativeBackendKWalletTestBase::CheckPasswordChanges(
} }
} }
// static
void NativeBackendKWalletTestBase::CheckPasswordChangesWithResult(
const PasswordStoreChangeList* expected,
const PasswordStoreChangeList* actual,
bool result) {
EXPECT_TRUE(result);
CheckPasswordChanges(*expected, *actual);
}
class NativeBackendKWalletTest : public NativeBackendKWalletTestBase { class NativeBackendKWalletTest : public NativeBackendKWalletTestBase {
protected: protected:
NativeBackendKWalletTest() NativeBackendKWalletTest()
...@@ -792,6 +807,73 @@ TEST_F(NativeBackendKWalletTest, ListLoginsAppends) { ...@@ -792,6 +807,73 @@ TEST_F(NativeBackendKWalletTest, ListLoginsAppends) {
CheckPasswordForms("Chrome Form Data (42)", expected); CheckPasswordForms("Chrome Form Data (42)", expected);
} }
TEST_F(NativeBackendKWalletTest, RemoveLoginsSyncedBetween) {
NativeBackendKWalletStub backend(42);
EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
base::Time now = base::Time::Now();
base::Time next_day = now + base::TimeDelta::FromDays(1);
form_google_.date_synced = now;
form_isc_.date_synced = next_day;
form_google_.date_created = base::Time();
form_isc_.date_created = base::Time();
BrowserThread::PostTask(
BrowserThread::DB,
FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
base::Unretained(&backend),
form_google_));
BrowserThread::PostTask(
BrowserThread::DB,
FROM_HERE,
base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
base::Unretained(&backend),
form_isc_));
PasswordStoreChangeList expected_changes;
expected_changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
PasswordStoreChangeList changes;
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::DB,
FROM_HERE,
base::Bind(&NativeBackendKWalletStub::RemoveLoginsSyncedBetween,
base::Unretained(&backend),
base::Time(),
next_day,
&changes),
base::Bind(&NativeBackendKWalletTest::CheckPasswordChangesWithResult,
&expected_changes,
&changes));
RunDBThread();
std::vector<const PasswordForm*> forms;
forms.push_back(&form_isc_);
ExpectationArray expected;
expected.push_back(make_pair(std::string(form_isc_.signon_realm), forms));
CheckPasswordForms("Chrome Form Data (42)", expected);
// Remove form_isc_.
expected_changes.clear();
expected_changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, form_isc_));
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::DB,
FROM_HERE,
base::Bind(&NativeBackendKWalletStub::RemoveLoginsSyncedBetween,
base::Unretained(&backend),
next_day,
base::Time(),
&changes),
base::Bind(&NativeBackendKWalletTest::CheckPasswordChangesWithResult,
&expected_changes,
&changes));
RunDBThread();
CheckPasswordForms("Chrome Form Data (42)", ExpectationArray());
}
// TODO(mdm): add more basic tests here at some point. // TODO(mdm): add more basic tests here at some point.
// (For example tests for storing >1 password per realm pickle.) // (For example tests for storing >1 password per realm pickle.)
......
...@@ -965,6 +965,40 @@ PasswordStoreChangeList PasswordStoreMac::RemoveLoginsCreatedBetweenImpl( ...@@ -965,6 +965,40 @@ PasswordStoreChangeList PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
return changes; return changes;
} }
PasswordStoreChangeList PasswordStoreMac::RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
PasswordStoreChangeList changes;
std::vector<PasswordForm*> forms;
if (login_metadata_db_->GetLoginsSyncedBetween(
delete_begin, delete_end, &forms)) {
if (login_metadata_db_->RemoveLoginsSyncedBetween(delete_begin,
delete_end)) {
// We can't delete from the Keychain by date because we may be sharing
// items with database entries that weren't in the delete range. Instead,
// we find all the Keychain items we own but aren't using any more and
// delete those.
std::vector<PasswordForm*> orphan_keychain_forms =
GetUnusedKeychainForms();
// This is inefficient, since we have to re-look-up each keychain item
// one at a time to delete it even though the search step already had a
// list of Keychain item references. If this turns out to be noticeably
// slow we'll need to rearchitect to allow the search and deletion steps
// to share.
RemoveKeychainForms(orphan_keychain_forms);
STLDeleteElements(&orphan_keychain_forms);
for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
it != forms.end();
++it) {
changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, **it));
}
}
}
return changes;
}
void PasswordStoreMac::GetLoginsImpl( void PasswordStoreMac::GetLoginsImpl(
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -60,6 +60,9 @@ class PasswordStoreMac : public password_manager::PasswordStore { ...@@ -60,6 +60,9 @@ class PasswordStoreMac : public password_manager::PasswordStore {
virtual password_manager::PasswordStoreChangeList virtual password_manager::PasswordStoreChangeList
RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin,
const base::Time& delete_end) OVERRIDE; const base::Time& delete_end) OVERRIDE;
virtual password_manager::PasswordStoreChangeList
RemoveLoginsSyncedBetweenImpl(base::Time delete_begin,
base::Time delete_end) OVERRIDE;
virtual void GetLoginsImpl( virtual void GetLoginsImpl(
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -110,6 +110,21 @@ PasswordStoreChangeList PasswordStoreX::RemoveLoginsCreatedBetweenImpl( ...@@ -110,6 +110,21 @@ PasswordStoreChangeList PasswordStoreX::RemoveLoginsCreatedBetweenImpl(
return changes; return changes;
} }
PasswordStoreChangeList PasswordStoreX::RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
CheckMigration();
PasswordStoreChangeList changes;
if (use_native_backend() &&
backend_->RemoveLoginsSyncedBetween(delete_begin, delete_end, &changes)) {
allow_fallback_ = false;
} else if (allow_default_store()) {
changes = PasswordStoreDefault::RemoveLoginsSyncedBetweenImpl(delete_begin,
delete_end);
}
return changes;
}
namespace { namespace {
struct LoginLessThan { struct LoginLessThan {
bool operator()(const PasswordForm* a, const PasswordForm* b) { bool operator()(const PasswordForm* a, const PasswordForm* b) {
......
...@@ -46,12 +46,21 @@ class PasswordStoreX : public password_manager::PasswordStoreDefault { ...@@ -46,12 +46,21 @@ class PasswordStoreX : public password_manager::PasswordStoreDefault {
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
password_manager::PasswordStoreChangeList* changes) = 0; password_manager::PasswordStoreChangeList* changes) = 0;
virtual bool RemoveLogin(const autofill::PasswordForm& form) = 0; virtual bool RemoveLogin(const autofill::PasswordForm& form) = 0;
virtual bool RemoveLoginsCreatedBetween(const base::Time& delete_begin,
const base::Time& delete_end) = 0; // Removes all logins created/synced from |delete_begin| onwards (inclusive)
// and before |delete_end|. You may use a null Time value to do an unbounded
// delete in either direction.
virtual bool RemoveLoginsCreatedBetween(base::Time delete_begin,
base::Time delete_end) = 0;
virtual bool RemoveLoginsSyncedBetween(
base::Time delete_begin,
base::Time delete_end,
password_manager::PasswordStoreChangeList* changes) = 0;
virtual bool GetLogins(const autofill::PasswordForm& form, virtual bool GetLogins(const autofill::PasswordForm& form,
PasswordFormList* forms) = 0; PasswordFormList* forms) = 0;
virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, virtual bool GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) = 0; PasswordFormList* forms) = 0;
virtual bool GetAutofillableLogins(PasswordFormList* forms) = 0; virtual bool GetAutofillableLogins(PasswordFormList* forms) = 0;
virtual bool GetBlacklistLogins(PasswordFormList* forms) = 0; virtual bool GetBlacklistLogins(PasswordFormList* forms) = 0;
...@@ -79,6 +88,9 @@ class PasswordStoreX : public password_manager::PasswordStoreDefault { ...@@ -79,6 +88,9 @@ class PasswordStoreX : public password_manager::PasswordStoreDefault {
virtual password_manager::PasswordStoreChangeList virtual password_manager::PasswordStoreChangeList
RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin, RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin,
const base::Time& delete_end) OVERRIDE; const base::Time& delete_end) OVERRIDE;
virtual password_manager::PasswordStoreChangeList
RemoveLoginsSyncedBetweenImpl(base::Time delete_begin,
base::Time delete_end) OVERRIDE;
virtual void GetLoginsImpl( virtual void GetLoginsImpl(
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -68,9 +68,15 @@ class FailingBackend : public PasswordStoreX::NativeBackend { ...@@ -68,9 +68,15 @@ class FailingBackend : public PasswordStoreX::NativeBackend {
} }
virtual bool RemoveLogin(const PasswordForm& form) OVERRIDE { return false; } virtual bool RemoveLogin(const PasswordForm& form) OVERRIDE { return false; }
virtual bool RemoveLoginsCreatedBetween( virtual bool RemoveLoginsCreatedBetween(base::Time delete_begin,
const base::Time& delete_begin, base::Time delete_end) OVERRIDE {
const base::Time& delete_end) OVERRIDE { return false;
}
virtual bool RemoveLoginsSyncedBetween(
base::Time delete_begin,
base::Time delete_end,
password_manager::PasswordStoreChangeList* changes) OVERRIDE {
return false; return false;
} }
...@@ -79,8 +85,8 @@ class FailingBackend : public PasswordStoreX::NativeBackend { ...@@ -79,8 +85,8 @@ class FailingBackend : public PasswordStoreX::NativeBackend {
return false; return false;
} }
virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, virtual bool GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) OVERRIDE { PasswordFormList* forms) OVERRIDE {
return false; return false;
} }
...@@ -121,9 +127,8 @@ class MockBackend : public PasswordStoreX::NativeBackend { ...@@ -121,9 +127,8 @@ class MockBackend : public PasswordStoreX::NativeBackend {
return true; return true;
} }
virtual bool RemoveLoginsCreatedBetween( virtual bool RemoveLoginsCreatedBetween(base::Time delete_begin,
const base::Time& delete_begin, base::Time delete_end) OVERRIDE {
const base::Time& delete_end) OVERRIDE {
for (size_t i = 0; i < all_forms_.size(); ++i) { for (size_t i = 0; i < all_forms_.size(); ++i) {
if (delete_begin <= all_forms_[i].date_created && if (delete_begin <= all_forms_[i].date_created &&
(delete_end.is_null() || all_forms_[i].date_created < delete_end)) (delete_end.is_null() || all_forms_[i].date_created < delete_end))
...@@ -132,6 +137,22 @@ class MockBackend : public PasswordStoreX::NativeBackend { ...@@ -132,6 +137,22 @@ class MockBackend : public PasswordStoreX::NativeBackend {
return true; return true;
} }
virtual bool RemoveLoginsSyncedBetween(
base::Time delete_begin,
base::Time delete_end,
password_manager::PasswordStoreChangeList* changes) OVERRIDE {
DCHECK(changes);
for (size_t i = 0; i < all_forms_.size(); ++i) {
if (delete_begin <= all_forms_[i].date_synced &&
(delete_end.is_null() || all_forms_[i].date_synced < delete_end)) {
changes->push_back(password_manager::PasswordStoreChange(
password_manager::PasswordStoreChange::REMOVE, all_forms_[i]));
erase(i--);
}
}
return true;
}
virtual bool GetLogins(const PasswordForm& form, virtual bool GetLogins(const PasswordForm& form,
PasswordFormList* forms) OVERRIDE { PasswordFormList* forms) OVERRIDE {
for (size_t i = 0; i < all_forms_.size(); ++i) for (size_t i = 0; i < all_forms_.size(); ++i)
...@@ -140,8 +161,8 @@ class MockBackend : public PasswordStoreX::NativeBackend { ...@@ -140,8 +161,8 @@ class MockBackend : public PasswordStoreX::NativeBackend {
return true; return true;
} }
virtual bool GetLoginsCreatedBetween(const base::Time& get_begin, virtual bool GetLoginsCreatedBetween(base::Time get_begin,
const base::Time& get_end, base::Time get_end,
PasswordFormList* forms) OVERRIDE { PasswordFormList* forms) OVERRIDE {
for (size_t i = 0; i < all_forms_.size(); ++i) for (size_t i = 0; i < all_forms_.size(); ++i)
if (get_begin <= all_forms_[i].date_created && if (get_begin <= all_forms_[i].date_created &&
......
...@@ -64,6 +64,16 @@ class PasswordStoreConsumerHelper ...@@ -64,6 +64,16 @@ class PasswordStoreConsumerHelper
DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper); DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
}; };
// PasswordForm::date_synced is a local field. Therefore it may be different
// across clients.
void ClearSyncDateField(std::vector<PasswordForm>* forms) {
for (std::vector<PasswordForm>::iterator it = forms->begin();
it != forms->end();
++it) {
it->date_synced = base::Time();
}
}
} // namespace } // namespace
namespace passwords_helper { namespace passwords_helper {
...@@ -137,6 +147,7 @@ bool ProfileContainsSamePasswordFormsAsVerifier(int index) { ...@@ -137,6 +147,7 @@ bool ProfileContainsSamePasswordFormsAsVerifier(int index) {
std::vector<PasswordForm> forms; std::vector<PasswordForm> forms;
GetLogins(GetVerifierPasswordStore(), verifier_forms); GetLogins(GetVerifierPasswordStore(), verifier_forms);
GetLogins(GetPasswordStore(index), forms); GetLogins(GetPasswordStore(index), forms);
ClearSyncDateField(&forms);
bool result = bool result =
password_manager::ContainsSamePasswordForms(verifier_forms, forms); password_manager::ContainsSamePasswordForms(verifier_forms, forms);
if (!result) { if (!result) {
...@@ -159,6 +170,8 @@ bool ProfilesContainSamePasswordForms(int index_a, int index_b) { ...@@ -159,6 +170,8 @@ bool ProfilesContainSamePasswordForms(int index_a, int index_b) {
std::vector<PasswordForm> forms_b; std::vector<PasswordForm> forms_b;
GetLogins(GetPasswordStore(index_a), forms_a); GetLogins(GetPasswordStore(index_a), forms_a);
GetLogins(GetPasswordStore(index_b), forms_b); GetLogins(GetPasswordStore(index_b), forms_b);
ClearSyncDateField(&forms_a);
ClearSyncDateField(&forms_b);
bool result = password_manager::ContainsSamePasswordForms(forms_a, forms_b); bool result = password_manager::ContainsSamePasswordForms(forms_a, forms_b);
if (!result) { if (!result) {
LOG(ERROR) << "Password forms in Profile" << index_a << ":"; LOG(ERROR) << "Password forms in Profile" << index_a << ":";
......
...@@ -354,19 +354,20 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { ...@@ -354,19 +354,20 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
// Replacement is necessary to deal with updating imported credentials. See // Replacement is necessary to deal with updating imported credentials. See
// crbug.com/349138 for details. // crbug.com/349138 for details.
sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
"UPDATE OR REPLACE logins SET " "UPDATE OR REPLACE logins SET "
"action_url = ?, " "action_url = ?, "
"password_value = ?, " "password_value = ?, "
"ssl_valid = ?, " "ssl_valid = ?, "
"preferred = ?, " "preferred = ?, "
"possible_usernames = ?, " "possible_usernames = ?, "
"times_used = ?, " "times_used = ?, "
"submit_element = ? " "submit_element = ?, "
"WHERE origin_url = ? AND " "date_synced = ? "
"username_element = ? AND " "WHERE origin_url = ? AND "
"username_value = ? AND " "username_element = ? AND "
"password_element = ? AND " "username_value = ? AND "
"signon_realm = ?")); "password_element = ? AND "
"signon_realm = ?"));
s.BindString(0, form.action.spec()); s.BindString(0, form.action.spec());
s.BindBlob(1, encrypted_password.data(), s.BindBlob(1, encrypted_password.data(),
static_cast<int>(encrypted_password.length())); static_cast<int>(encrypted_password.length()));
...@@ -376,12 +377,13 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) { ...@@ -376,12 +377,13 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form) {
s.BindBlob(4, pickle.data(), pickle.size()); s.BindBlob(4, pickle.data(), pickle.size());
s.BindInt(5, form.times_used); s.BindInt(5, form.times_used);
s.BindString16(6, form.submit_element); s.BindString16(6, form.submit_element);
s.BindInt64(7, form.date_synced.ToInternalValue());
s.BindString(7, form.origin.spec()); s.BindString(8, form.origin.spec());
s.BindString16(8, form.username_element); s.BindString16(9, form.username_element);
s.BindString16(9, form.username_value); s.BindString16(10, form.username_value);
s.BindString16(10, form.password_element); s.BindString16(11, form.password_element);
s.BindString(11, form.signon_realm); s.BindString(12, form.signon_realm);
if (!s.Run()) if (!s.Run())
return PasswordStoreChangeList(); return PasswordStoreChangeList();
...@@ -425,6 +427,19 @@ bool LoginDatabase::RemoveLoginsCreatedBetween(const base::Time delete_begin, ...@@ -425,6 +427,19 @@ bool LoginDatabase::RemoveLoginsCreatedBetween(const base::Time delete_begin,
return s.Run(); return s.Run();
} }
bool LoginDatabase::RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end) {
sql::Statement s(db_.GetCachedStatement(
SQL_FROM_HERE,
"DELETE FROM logins WHERE date_synced >= ? AND date_synced < ?"));
s.BindInt64(0, delete_begin.ToInternalValue());
s.BindInt64(1,
delete_end.is_null() ? base::Time::Max().ToInternalValue()
: delete_end.ToInternalValue());
return s.Run();
}
LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement( LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
PasswordForm* form, PasswordForm* form,
sql::Statement& s) const { sql::Statement& s) const {
...@@ -603,6 +618,38 @@ bool LoginDatabase::GetLoginsCreatedBetween( ...@@ -603,6 +618,38 @@ bool LoginDatabase::GetLoginsCreatedBetween(
return s.Succeeded(); return s.Succeeded();
} }
bool LoginDatabase::GetLoginsSyncedBetween(
const base::Time begin,
const base::Time end,
std::vector<autofill::PasswordForm*>* forms) const {
DCHECK(forms);
sql::Statement s(db_.GetCachedStatement(
SQL_FROM_HERE,
"SELECT origin_url, action_url, username_element, username_value, "
"password_element, password_value, submit_element, signon_realm, "
"ssl_valid, preferred, date_created, blacklisted_by_user, "
"scheme, password_type, possible_usernames, times_used, form_data, "
"use_additional_auth, date_synced FROM logins "
"WHERE date_synced >= ? AND date_synced < ?"
"ORDER BY origin_url"));
s.BindInt64(0, begin.ToInternalValue());
s.BindInt64(1,
end.is_null() ? base::Time::Max().ToInternalValue()
: end.ToInternalValue());
while (s.Step()) {
scoped_ptr<PasswordForm> new_form(new PasswordForm());
EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s);
if (result == ENCRYPTION_RESULT_SERVICE_FAILURE)
return false;
if (result == ENCRYPTION_RESULT_ITEM_FAILURE)
continue;
DCHECK(result == ENCRYPTION_RESULT_SUCCESS);
forms->push_back(new_form.release());
}
return s.Succeeded();
}
bool LoginDatabase::GetAutofillableLogins( bool LoginDatabase::GetAutofillableLogins(
std::vector<PasswordForm*>* forms) const { std::vector<PasswordForm*>* forms) const {
return GetAllLoginsWithBlacklistSetting(false, forms); return GetAllLoginsWithBlacklistSetting(false, forms);
......
...@@ -54,6 +54,12 @@ class LoginDatabase { ...@@ -54,6 +54,12 @@ class LoginDatabase {
bool RemoveLoginsCreatedBetween(const base::Time delete_begin, bool RemoveLoginsCreatedBetween(const base::Time delete_begin,
const base::Time delete_end); const base::Time delete_end);
// Removes all logins synced from |delete_begin| onwards (inclusive) and
// before |delete_end|. You may use a null Time value to do an unbounded
// delete in either direction.
bool RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end);
// Loads a list of matching password forms into the specified vector |forms|. // Loads a list of matching password forms into the specified vector |forms|.
// The list will contain all possibly relevant entries to the observed |form|, // The list will contain all possibly relevant entries to the observed |form|,
// including blacklisted matches. // including blacklisted matches.
...@@ -64,8 +70,16 @@ class LoginDatabase { ...@@ -64,8 +70,16 @@ class LoginDatabase {
// You may use a null Time value to do an unbounded search in either // You may use a null Time value to do an unbounded search in either
// direction. // direction.
bool GetLoginsCreatedBetween( bool GetLoginsCreatedBetween(
const base::Time begin, base::Time begin,
const base::Time end, base::Time end,
std::vector<autofill::PasswordForm*>* forms) const;
// Loads all logins synced from |begin| onwards (inclusive) and before |end|.
// You may use a null Time value to do an unbounded search in either
// direction.
bool GetLoginsSyncedBetween(
base::Time begin,
base::Time end,
std::vector<autofill::PasswordForm*>* forms) const; std::vector<autofill::PasswordForm*>* forms) const;
// Loads the complete list of autofillable password forms (i.e., not blacklist // Loads the complete list of autofillable password forms (i.e., not blacklist
......
...@@ -577,9 +577,11 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) { ...@@ -577,9 +577,11 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingRegexp) {
EXPECT_EQ(0U, result.size()); EXPECT_EQ(0U, result.size());
} }
static bool AddTimestampedLogin(LoginDatabase* db, std::string url, static bool AddTimestampedLogin(LoginDatabase* db,
std::string url,
const std::string& unique_string, const std::string& unique_string,
const base::Time& time) { const base::Time& time,
bool date_is_creation) {
// Example password form. // Example password form.
PasswordForm form; PasswordForm form;
form.origin = GURL(url + std::string("/LoginAuth")); form.origin = GURL(url + std::string("/LoginAuth"));
...@@ -588,7 +590,10 @@ static bool AddTimestampedLogin(LoginDatabase* db, std::string url, ...@@ -588,7 +590,10 @@ static bool AddTimestampedLogin(LoginDatabase* db, std::string url,
form.password_element = ASCIIToUTF16(unique_string); form.password_element = ASCIIToUTF16(unique_string);
form.submit_element = ASCIIToUTF16("signIn"); form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = url; form.signon_realm = url;
form.date_created = time; if (date_is_creation)
form.date_created = time;
else
form.date_synced = time;
return db->AddLogin(form) == AddChangeForForm(form); return db->AddLogin(form) == AddChangeForForm(form);
} }
...@@ -610,11 +615,11 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) { ...@@ -610,11 +615,11 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
base::TimeDelta one_day = base::TimeDelta::FromDays(1); base::TimeDelta one_day = base::TimeDelta::FromDays(1);
// Create one with a 0 time. // Create one with a 0 time.
EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time())); EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), true));
// Create one for now and +/- 1 day. // Create one for now and +/- 1 day.
EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day)); EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, true));
EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now)); EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, true));
EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day)); EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, true));
// Verify inserts worked. // Verify inserts worked.
EXPECT_TRUE(db_.GetAutofillableLogins(&result)); EXPECT_TRUE(db_.GetAutofillableLogins(&result));
...@@ -642,6 +647,49 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) { ...@@ -642,6 +647,49 @@ TEST_F(LoginDatabaseTest, ClearPrivateData_SavedPasswords) {
EXPECT_EQ(0U, result.size()); EXPECT_EQ(0U, result.size());
} }
TEST_F(LoginDatabaseTest, RemoveLoginsSyncedBetween) {
ScopedVector<autofill::PasswordForm> result;
base::Time now = base::Time::Now();
base::TimeDelta one_day = base::TimeDelta::FromDays(1);
// Create one with a 0 time.
EXPECT_TRUE(AddTimestampedLogin(&db_, "1", "foo1", base::Time(), false));
// Create one for now and +/- 1 day.
EXPECT_TRUE(AddTimestampedLogin(&db_, "2", "foo2", now - one_day, false));
EXPECT_TRUE(AddTimestampedLogin(&db_, "3", "foo3", now, false));
EXPECT_TRUE(AddTimestampedLogin(&db_, "4", "foo4", now + one_day, false));
// Verify inserts worked.
EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
EXPECT_EQ(4U, result.size());
result.clear();
// Get everything from today's date and on.
EXPECT_TRUE(db_.GetLoginsSyncedBetween(now, base::Time(), &result.get()));
ASSERT_EQ(2U, result.size());
EXPECT_EQ("3", result[0]->signon_realm);
EXPECT_EQ("4", result[1]->signon_realm);
result.clear();
// Delete everything from today's date and on.
db_.RemoveLoginsSyncedBetween(now, base::Time());
// Should have deleted half of what we inserted.
EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
ASSERT_EQ(2U, result.size());
EXPECT_EQ("1", result[0]->signon_realm);
EXPECT_EQ("2", result[1]->signon_realm);
result.clear();
// Delete with 0 date (should delete all).
db_.RemoveLoginsSyncedBetween(base::Time(), now);
// Verify nothing is left.
EXPECT_TRUE(db_.GetAutofillableLogins(&result.get()));
EXPECT_EQ(0U, result.size());
}
TEST_F(LoginDatabaseTest, BlacklistedLogins) { TEST_F(LoginDatabaseTest, BlacklistedLogins) {
std::vector<PasswordForm*> result; std::vector<PasswordForm*> result;
...@@ -814,6 +862,7 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) { ...@@ -814,6 +862,7 @@ TEST_F(LoginDatabaseTest, UpdateOverlappingCredentials) {
// Simulate the user changing their password. // Simulate the user changing their password.
complete_form.password_value = ASCIIToUTF16("new_password"); complete_form.password_value = ASCIIToUTF16("new_password");
complete_form.date_synced = base::Time::Now();
EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form)); EXPECT_EQ(UpdateChangeForForm(complete_form), db_.UpdateLogin(complete_form));
// Both still exist now. // Both still exist now.
......
...@@ -36,6 +36,8 @@ class MockPasswordStore : public PasswordStore { ...@@ -36,6 +36,8 @@ class MockPasswordStore : public PasswordStore {
PasswordStoreChangeList(const autofill::PasswordForm&)); PasswordStoreChangeList(const autofill::PasswordForm&));
MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl, MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl,
PasswordStoreChangeList(const base::Time&, const base::Time&)); PasswordStoreChangeList(const base::Time&, const base::Time&));
MOCK_METHOD2(RemoveLoginsSyncedBetweenImpl,
PasswordStoreChangeList(base::Time, base::Time));
MOCK_METHOD3(GetLoginsImpl, MOCK_METHOD3(GetLoginsImpl,
void(const autofill::PasswordForm& form, void(const autofill::PasswordForm& form,
PasswordStore::AuthorizationPromptPolicy prompt_policy, PasswordStore::AuthorizationPromptPolicy prompt_policy,
......
...@@ -112,6 +112,17 @@ void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin, ...@@ -112,6 +112,17 @@ void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin,
this, delete_begin, delete_end))); this, delete_begin, delete_end)));
} }
void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end) {
ScheduleTask(
base::Bind(&PasswordStore::WrapModificationTask,
this,
base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenImpl,
this,
delete_begin,
delete_end)));
}
void PasswordStore::GetLogins( void PasswordStore::GetLogins(
const PasswordForm& form, const PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -142,6 +142,10 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -142,6 +142,10 @@ class PasswordStore : protected PasswordStoreSync,
virtual void RemoveLoginsCreatedBetween(const base::Time& delete_begin, virtual void RemoveLoginsCreatedBetween(const base::Time& delete_begin,
const base::Time& delete_end); const base::Time& delete_end);
// Removes all logins synced in the given date range.
virtual void RemoveLoginsSyncedBetween(base::Time delete_begin,
base::Time delete_end);
// Searches for a matching PasswordForm, and notifies |consumer| on // Searches for a matching PasswordForm, and notifies |consumer| on
// completion. The request will be cancelled if the consumer is destroyed. // completion. The request will be cancelled if the consumer is destroyed.
// |prompt_policy| indicates whether it's permissible to prompt the user to // |prompt_policy| indicates whether it's permissible to prompt the user to
...@@ -215,6 +219,11 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -215,6 +219,11 @@ class PasswordStore : protected PasswordStoreSync,
virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl( virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl(
const base::Time& delete_begin, const base::Time& delete_end) = 0; const base::Time& delete_begin, const base::Time& delete_end) = 0;
// Synchronous implementation to remove the given logins.
virtual PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) = 0;
typedef base::Callback<void(const std::vector<autofill::PasswordForm*>&)> typedef base::Callback<void(const std::vector<autofill::PasswordForm*>&)>
ConsumerCallbackRunner; // Owns all PasswordForms in the vector. ConsumerCallbackRunner; // Owns all PasswordForms in the vector.
......
...@@ -70,6 +70,25 @@ PasswordStoreChangeList PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl( ...@@ -70,6 +70,25 @@ PasswordStoreChangeList PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(
return changes; return changes;
} }
PasswordStoreChangeList PasswordStoreDefault::RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) {
std::vector<PasswordForm*> forms;
PasswordStoreChangeList changes;
if (login_db_->GetLoginsSyncedBetween(delete_begin, delete_end, &forms)) {
if (login_db_->RemoveLoginsSyncedBetween(delete_begin, delete_end)) {
for (std::vector<PasswordForm*>::const_iterator it = forms.begin();
it != forms.end();
++it) {
changes.push_back(
PasswordStoreChange(PasswordStoreChange::REMOVE, **it));
}
}
}
STLDeleteElements(&forms);
return changes;
}
void PasswordStoreDefault::GetLoginsImpl( void PasswordStoreDefault::GetLoginsImpl(
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -36,6 +36,9 @@ class PasswordStoreDefault : public PasswordStore { ...@@ -36,6 +36,9 @@ class PasswordStoreDefault : public PasswordStore {
const autofill::PasswordForm& form) OVERRIDE; const autofill::PasswordForm& form) OVERRIDE;
virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl( virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl(
const base::Time& delete_begin, const base::Time& delete_end) OVERRIDE; const base::Time& delete_begin, const base::Time& delete_end) OVERRIDE;
virtual PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) OVERRIDE;
virtual void GetLoginsImpl( virtual void GetLoginsImpl(
const autofill::PasswordForm& form, const autofill::PasswordForm& form,
AuthorizationPromptPolicy prompt_policy, AuthorizationPromptPolicy prompt_policy,
......
...@@ -221,6 +221,7 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges( ...@@ -221,6 +221,7 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
ScopedVector<autofill::PasswordForm> new_sync_entries; ScopedVector<autofill::PasswordForm> new_sync_entries;
ScopedVector<autofill::PasswordForm> updated_sync_entries; ScopedVector<autofill::PasswordForm> updated_sync_entries;
ScopedVector<autofill::PasswordForm> deleted_entries; ScopedVector<autofill::PasswordForm> deleted_entries;
base::Time time_now = base::Time::Now();
for (syncer::SyncChangeList::const_iterator it = change_list.begin(); for (syncer::SyncChangeList::const_iterator it = change_list.begin();
it != change_list.end(); it != change_list.end();
...@@ -231,10 +232,12 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges( ...@@ -231,10 +232,12 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges(
form.get()); form.get());
switch (it->change_type()) { switch (it->change_type()) {
case syncer::SyncChange::ACTION_ADD: { case syncer::SyncChange::ACTION_ADD: {
form->date_synced = time_now;
new_sync_entries.push_back(form.release()); new_sync_entries.push_back(form.release());
break; break;
} }
case syncer::SyncChange::ACTION_UPDATE: { case syncer::SyncChange::ACTION_UPDATE: {
form->date_synced = time_now;
updated_sync_entries.push_back(form.release()); updated_sync_entries.push_back(form.release());
break; break;
} }
...@@ -368,10 +371,12 @@ void PasswordSyncableService::CreateOrUpdateEntry( ...@@ -368,10 +371,12 @@ void PasswordSyncableService::CreateOrUpdateEntry(
// Check whether the data from sync is already in the password store. // Check whether the data from sync is already in the password store.
PasswordEntryMap::iterator existing_local_entry_iter = PasswordEntryMap::iterator existing_local_entry_iter =
umatched_data_from_password_db->find(tag); umatched_data_from_password_db->find(tag);
base::Time time_now = base::Time::Now();
if (existing_local_entry_iter == umatched_data_from_password_db->end()) { if (existing_local_entry_iter == umatched_data_from_password_db->end()) {
// The sync data is not in the password store, so we need to create it in // The sync data is not in the password store, so we need to create it in
// the password store. Add the entry to the new_entries list. // the password store. Add the entry to the new_entries list.
scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm); scoped_ptr<autofill::PasswordForm> new_password(new autofill::PasswordForm);
new_password->date_synced = time_now;
PasswordFromSpecifics(password_specifics, new_password.get()); PasswordFromSpecifics(password_specifics, new_password.get());
new_sync_entries->push_back(new_password.release()); new_sync_entries->push_back(new_password.release());
} else { } else {
...@@ -384,6 +389,7 @@ void PasswordSyncableService::CreateOrUpdateEntry( ...@@ -384,6 +389,7 @@ void PasswordSyncableService::CreateOrUpdateEntry(
case IDENTICAL: case IDENTICAL:
break; break;
case SYNC: case SYNC:
new_password->date_synced = time_now;
updated_sync_entries->push_back(new_password.release()); updated_sync_entries->push_back(new_password.release());
break; break;
case LOCAL: case LOCAL:
......
...@@ -82,6 +82,25 @@ SyncChange CreateSyncChange(const autofill::PasswordForm& password, ...@@ -82,6 +82,25 @@ SyncChange CreateSyncChange(const autofill::PasswordForm& password,
return SyncChange(FROM_HERE, type, data); return SyncChange(FROM_HERE, type, data);
} }
class FormFinder {
public:
explicit FormFinder(const autofill::PasswordForm& form) : form_(form) {}
~FormFinder() {}
bool operator()(const autofill::PasswordForm& form) const;
private:
const autofill::PasswordForm form_;
};
bool FormFinder::operator()(const autofill::PasswordForm& form) const {
return form.origin == form_.origin &&
form.username_element == form_.username_element &&
form.username_value == form_.username_value &&
form.password_element == form_.password_element &&
form.signon_realm == form_.signon_realm;
}
// A testable implementation of the |PasswordSyncableService| that mocks // A testable implementation of the |PasswordSyncableService| that mocks
// out all interaction with the password database. // out all interaction with the password database.
class MockPasswordSyncableService : public PasswordSyncableService { class MockPasswordSyncableService : public PasswordSyncableService {
...@@ -267,9 +286,15 @@ PasswordStoreChangeList PasswordStoreDataVerifier::VerifyChange( ...@@ -267,9 +286,15 @@ PasswordStoreChangeList PasswordStoreDataVerifier::VerifyChange(
PasswordStoreChange::Type type, PasswordStoreChange::Type type,
const autofill::PasswordForm& password, const autofill::PasswordForm& password,
std::vector<autofill::PasswordForm>* password_list) { std::vector<autofill::PasswordForm>* password_list) {
std::vector<autofill::PasswordForm>::iterator it = std::vector<autofill::PasswordForm>::iterator it = std::find_if(
std::find(password_list->begin(), password_list->end(), password); password_list->begin(), password_list->end(), FormFinder(password));
EXPECT_NE(password_list->end(), it); EXPECT_NE(password_list->end(), it);
PasswordsEqual(GetPasswordSpecifics(SyncDataFromPassword(*it)),
GetPasswordSpecifics(SyncDataFromPassword(password)));
if (type != PasswordStoreChange::REMOVE) {
EXPECT_FALSE(password.date_synced.is_null()) << password.signon_realm;
EXPECT_FALSE(password.date_synced.is_max()) << password.signon_realm;
}
password_list->erase(it); password_list->erase(it);
return PasswordStoreChangeList(1, PasswordStoreChange(type, password)); return PasswordStoreChangeList(1, PasswordStoreChange(type, password));
} }
......
...@@ -111,6 +111,13 @@ PasswordStoreChangeList TestPasswordStore::RemoveLoginsCreatedBetweenImpl( ...@@ -111,6 +111,13 @@ PasswordStoreChangeList TestPasswordStore::RemoveLoginsCreatedBetweenImpl(
return changes; return changes;
} }
PasswordStoreChangeList TestPasswordStore::RemoveLoginsSyncedBetweenImpl(
base::Time begin,
base::Time end) {
PasswordStoreChangeList changes;
return changes;
}
bool TestPasswordStore::FillAutofillableLogins( bool TestPasswordStore::FillAutofillableLogins(
std::vector<autofill::PasswordForm*>* forms) { std::vector<autofill::PasswordForm*>* forms) {
return true; return true;
......
...@@ -61,6 +61,9 @@ class TestPasswordStore : public PasswordStore { ...@@ -61,6 +61,9 @@ class TestPasswordStore : public PasswordStore {
virtual void ReportMetricsImpl() OVERRIDE {} virtual void ReportMetricsImpl() OVERRIDE {}
virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl( virtual PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl(
const base::Time& begin, const base::Time& end) OVERRIDE; const base::Time& begin, const base::Time& end) OVERRIDE;
virtual PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
base::Time delete_begin,
base::Time delete_end) OVERRIDE;
virtual void GetAutofillableLoginsImpl( virtual void GetAutofillableLoginsImpl(
PasswordStore::GetLoginsRequest* request) OVERRIDE {} PasswordStore::GetLoginsRequest* request) OVERRIDE {}
virtual void GetBlacklistLoginsImpl( virtual void GetBlacklistLoginsImpl(
......
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