Commit a8cf3312 authored by Victor Hugo Vianna Silva's avatar Victor Hugo Vianna Silva Committed by Commit Bot

[b4p] Introduce JS APIs for batch deletions of passwords/blacklists

This CL introduces removeSavedPasswords and removePasswordExceptions
APIs to chrome.passwordsPrivate, which allow deleting batches of
passwords/blacklists that are entirely restored upon call to
undoRemoveSavedPasswordOrException.

This is achieved by plumbing the APIs introduced in crrev.com/c/2193695.
In order to minimize unnecessary function duplication, all the C++
intermediary APIs now take batches as arguments. Only JS still exposes
APIs for individual deletion.

In future CLs, the JS APIs will be used to allow simultaneously deleting
versions of a same password stored in different PasswordStore's.

Bug: 1049141
Change-Id: I5852b1c4375caef4ac3e167ccd0fa9c30eeef9e0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2199148
Commit-Queue: Victor Vianna <victorvianna@google.com>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770034}
parent a634d446
...@@ -77,7 +77,16 @@ ResponseAction PasswordsPrivateRemoveSavedPasswordFunction::Run() { ...@@ -77,7 +77,16 @@ ResponseAction PasswordsPrivateRemoveSavedPasswordFunction::Run() {
auto parameters = auto parameters =
api::passwords_private::RemoveSavedPassword::Params::Create(*args_); api::passwords_private::RemoveSavedPassword::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters); EXTENSION_FUNCTION_VALIDATE(parameters);
GetDelegate(browser_context())->RemoveSavedPassword(parameters->id); GetDelegate(browser_context())->RemoveSavedPasswords({parameters->id});
return RespondNow(NoArguments());
}
// PasswordsPrivateRemoveSavedPasswordsFunction
ResponseAction PasswordsPrivateRemoveSavedPasswordsFunction::Run() {
auto parameters =
api::passwords_private::RemoveSavedPasswords::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters);
GetDelegate(browser_context())->RemoveSavedPasswords(parameters->ids);
return RespondNow(NoArguments()); return RespondNow(NoArguments());
} }
...@@ -86,7 +95,16 @@ ResponseAction PasswordsPrivateRemovePasswordExceptionFunction::Run() { ...@@ -86,7 +95,16 @@ ResponseAction PasswordsPrivateRemovePasswordExceptionFunction::Run() {
auto parameters = auto parameters =
api::passwords_private::RemovePasswordException::Params::Create(*args_); api::passwords_private::RemovePasswordException::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters); EXTENSION_FUNCTION_VALIDATE(parameters);
GetDelegate(browser_context())->RemovePasswordException(parameters->id); GetDelegate(browser_context())->RemovePasswordExceptions({parameters->id});
return RespondNow(NoArguments());
}
// PasswordsPrivateRemovePasswordExceptionsFunction
ResponseAction PasswordsPrivateRemovePasswordExceptionsFunction::Run() {
auto parameters =
api::passwords_private::RemovePasswordExceptions::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters);
GetDelegate(browser_context())->RemovePasswordExceptions(parameters->ids);
return RespondNow(NoArguments()); return RespondNow(NoArguments());
} }
......
...@@ -54,6 +54,18 @@ class PasswordsPrivateRemoveSavedPasswordFunction : public ExtensionFunction { ...@@ -54,6 +54,18 @@ class PasswordsPrivateRemoveSavedPasswordFunction : public ExtensionFunction {
ResponseAction Run() override; ResponseAction Run() override;
}; };
class PasswordsPrivateRemoveSavedPasswordsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.removeSavedPasswords",
PASSWORDSPRIVATE_REMOVESAVEDPASSWORDS)
protected:
~PasswordsPrivateRemoveSavedPasswordsFunction() override = default;
// ExtensionFunction overrides.
ResponseAction Run() override;
};
class PasswordsPrivateRemovePasswordExceptionFunction class PasswordsPrivateRemovePasswordExceptionFunction
: public ExtensionFunction { : public ExtensionFunction {
public: public:
...@@ -67,6 +79,19 @@ class PasswordsPrivateRemovePasswordExceptionFunction ...@@ -67,6 +79,19 @@ class PasswordsPrivateRemovePasswordExceptionFunction
ResponseAction Run() override; ResponseAction Run() override;
}; };
class PasswordsPrivateRemovePasswordExceptionsFunction
: public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.removePasswordExceptions",
PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS)
protected:
~PasswordsPrivateRemovePasswordExceptionsFunction() override = default;
// ExtensionFunction overrides.
ResponseAction Run() override;
};
class PasswordsPrivateUndoRemoveSavedPasswordOrExceptionFunction class PasswordsPrivateUndoRemoveSavedPasswordOrExceptionFunction
: public ExtensionFunction { : public ExtensionFunction {
public: public:
......
...@@ -126,12 +126,24 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, ...@@ -126,12 +126,24 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
<< message_; << message_;
} }
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
RemoveAndUndoRemoveSavedPasswordsBatch) {
EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemoveSavedPasswordsBatch"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
RemoveAndUndoRemovePasswordException) { RemoveAndUndoRemovePasswordException) {
EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemovePasswordException")) EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemovePasswordException"))
<< message_; << message_;
} }
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
RemoveAndUndoRemovePasswordExceptionsBatch) {
EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemovePasswordExceptionsBatch"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestPlaintextPassword) { IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestPlaintextPassword) {
EXPECT_TRUE(RunPasswordsSubtest("requestPlaintextPassword")) << message_; EXPECT_TRUE(RunPasswordsSubtest("requestPlaintextPassword")) << message_;
} }
......
...@@ -65,15 +65,13 @@ class PasswordsPrivateDelegate : public KeyedService { ...@@ -65,15 +65,13 @@ class PasswordsPrivateDelegate : public KeyedService {
base::string16 new_username, base::string16 new_username,
base::Optional<base::string16> new_password) = 0; base::Optional<base::string16> new_password) = 0;
// Removes the saved password entry corresponding to the |id| generated for // Removes the saved password entries corresponding to the |ids| generated for
// each entry of the password list. // each entry of the password list. Any invalid id will be ignored.
// |id| the id created when going over the list of saved passwords. virtual void RemoveSavedPasswords(const std::vector<int>& ids) = 0;
virtual void RemoveSavedPassword(int id) = 0;
// Removes the saved password exception entry corresponding set in the // Removes the password exceptions entries corresponding corresponding to
// given |id| // |ids|. Any invalid id will be ignored.
// |id| The id for the exception url entry being removed. virtual void RemovePasswordExceptions(const std::vector<int>& ids) = 0;
virtual void RemovePasswordException(int id) = 0;
// Undoes the last removal of a saved password or exception. // Undoes the last removal of a saved password or exception.
virtual void UndoRemoveSavedPasswordOrException() = 0; virtual void UndoRemoveSavedPasswordOrException() = 0;
......
...@@ -122,6 +122,20 @@ password_manager::PlaintextReason ConvertPlaintextReason( ...@@ -122,6 +122,20 @@ password_manager::PlaintextReason ConvertPlaintextReason(
return password_manager::PlaintextReason::kView; return password_manager::PlaintextReason::kView;
} }
// Gets all the existing keys in |generator| corresponding to |ids|. If no key
// is found for an id, it is simply ignored.
std::vector<std::string> GetSortKeys(
const extensions::IdGenerator<std::string>& generator,
const std::vector<int> ids) {
std::vector<std::string> sort_keys;
sort_keys.reserve(ids.size());
for (int id : ids) {
if (const std::string* sort_key = generator.TryGetKey(id))
sort_keys.emplace_back(*sort_key);
}
return sort_keys;
}
} // namespace } // namespace
namespace extensions { namespace extensions {
...@@ -197,28 +211,30 @@ void PasswordsPrivateDelegateImpl::ChangeSavedPassword( ...@@ -197,28 +211,30 @@ void PasswordsPrivateDelegateImpl::ChangeSavedPassword(
*sort_key, std::move(new_username), std::move(new_password)); *sort_key, std::move(new_username), std::move(new_password));
} }
void PasswordsPrivateDelegateImpl::RemoveSavedPassword(int id) { void PasswordsPrivateDelegateImpl::RemoveSavedPasswords(
const std::vector<int>& ids) {
ExecuteFunction( ExecuteFunction(
base::Bind(&PasswordsPrivateDelegateImpl::RemoveSavedPasswordInternal, base::Bind(&PasswordsPrivateDelegateImpl::RemoveSavedPasswordsInternal,
base::Unretained(this), id)); base::Unretained(this), ids));
} }
void PasswordsPrivateDelegateImpl::RemoveSavedPasswordInternal(int id) { void PasswordsPrivateDelegateImpl::RemoveSavedPasswordsInternal(
const std::string* sort_key = password_id_generator_.TryGetKey(id); const std::vector<int>& ids) {
if (sort_key) password_manager_presenter_->RemoveSavedPasswords(
password_manager_presenter_->RemoveSavedPassword(*sort_key); GetSortKeys(password_id_generator_, ids));
} }
void PasswordsPrivateDelegateImpl::RemovePasswordException(int id) { void PasswordsPrivateDelegateImpl::RemovePasswordExceptions(
ExecuteFunction( const std::vector<int>& ids) {
base::Bind(&PasswordsPrivateDelegateImpl::RemovePasswordExceptionInternal, ExecuteFunction(base::Bind(
base::Unretained(this), id)); &PasswordsPrivateDelegateImpl::RemovePasswordExceptionsInternal,
base::Unretained(this), ids));
} }
void PasswordsPrivateDelegateImpl::RemovePasswordExceptionInternal(int id) { void PasswordsPrivateDelegateImpl::RemovePasswordExceptionsInternal(
const std::string* sort_key = exception_id_generator_.TryGetKey(id); const std::vector<int>& ids) {
if (sort_key) password_manager_presenter_->RemovePasswordExceptions(
password_manager_presenter_->RemovePasswordException(*sort_key); GetSortKeys(exception_id_generator_, ids));
} }
void PasswordsPrivateDelegateImpl::UndoRemoveSavedPasswordOrException() { void PasswordsPrivateDelegateImpl::UndoRemoveSavedPasswordOrException() {
......
...@@ -53,8 +53,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, ...@@ -53,8 +53,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
int id, int id,
base::string16 new_username, base::string16 new_username,
base::Optional<base::string16> new_password) override; base::Optional<base::string16> new_password) override;
void RemoveSavedPassword(int id) override; void RemoveSavedPasswords(const std::vector<int>& ids) override;
void RemovePasswordException(int id) override; void RemovePasswordExceptions(const std::vector<int>& ids) override;
void UndoRemoveSavedPasswordOrException() override; void UndoRemoveSavedPasswordOrException() override;
void RequestPlaintextPassword(int id, void RequestPlaintextPassword(int id,
api::passwords_private::PlaintextReason reason, api::passwords_private::PlaintextReason reason,
...@@ -123,8 +123,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, ...@@ -123,8 +123,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
void SendSavedPasswordsList(); void SendSavedPasswordsList();
void SendPasswordExceptionsList(); void SendPasswordExceptionsList();
void RemoveSavedPasswordInternal(int id); void RemoveSavedPasswordsInternal(const std::vector<int>& ids);
void RemovePasswordExceptionInternal(int id); void RemovePasswordExceptionsInternal(const std::vector<int>& ids);
void UndoRemoveSavedPasswordOrExceptionInternal(); void UndoRemoveSavedPasswordOrExceptionInternal();
// Callback for when the password list has been written to the destination. // Callback for when the password list has been written to the destination.
......
...@@ -72,36 +72,55 @@ void TestPasswordsPrivateDelegate::ChangeSavedPassword( ...@@ -72,36 +72,55 @@ void TestPasswordsPrivateDelegate::ChangeSavedPassword(
SendSavedPasswordsList(); SendSavedPasswordsList();
} }
void TestPasswordsPrivateDelegate::RemoveSavedPassword(int id) { void TestPasswordsPrivateDelegate::RemoveSavedPasswords(
const std::vector<int>& ids) {
if (current_entries_.empty()) if (current_entries_.empty())
return; return;
// Since this is just mock data, remove the first entry regardless of // Since this is just mock data, remove the first |ids.size()| elements
// the data contained. // regardless of the data contained.
last_deleted_entry_ = std::move(current_entries_.front()); auto first_remaining = (ids.size() <= current_entries_.size())
current_entries_.erase(current_entries_.begin()); ? current_entries_.begin() + ids.size()
: current_entries_.end();
last_deleted_entries_batch_.assign(
std::make_move_iterator(current_entries_.begin()),
std::make_move_iterator(first_remaining));
current_entries_.erase(current_entries_.begin(), first_remaining);
SendSavedPasswordsList(); SendSavedPasswordsList();
} }
void TestPasswordsPrivateDelegate::RemovePasswordException(int id) { void TestPasswordsPrivateDelegate::RemovePasswordExceptions(
// Since this is just mock data, remove the first entry regardless of const std::vector<int>& ids) {
// the data contained. if (current_exceptions_.empty())
last_deleted_exception_ = std::move(current_exceptions_.front()); return;
current_exceptions_.erase(current_exceptions_.begin());
// Since this is just mock data, remove the first |ids.size()| elements
// regardless of the data contained.
auto first_remaining = (ids.size() <= current_exceptions_.size())
? current_exceptions_.begin() + ids.size()
: current_exceptions_.end();
last_deleted_exceptions_batch_.assign(
std::make_move_iterator(current_exceptions_.begin()),
std::make_move_iterator(first_remaining));
current_exceptions_.erase(current_exceptions_.begin(), first_remaining);
SendPasswordExceptionsList(); SendPasswordExceptionsList();
} }
// Simplified version of undo logic, only use for testing. // Simplified version of undo logic, only use for testing.
void TestPasswordsPrivateDelegate::UndoRemoveSavedPasswordOrException() { void TestPasswordsPrivateDelegate::UndoRemoveSavedPasswordOrException() {
if (last_deleted_entry_) { if (!last_deleted_entries_batch_.empty()) {
current_entries_.insert(current_entries_.begin(), current_entries_.insert(
std::move(*last_deleted_entry_)); current_entries_.begin(),
last_deleted_entry_ = base::nullopt; std::make_move_iterator(last_deleted_entries_batch_.begin()),
std::make_move_iterator(last_deleted_entries_batch_.end()));
last_deleted_entries_batch_.clear();
SendSavedPasswordsList(); SendSavedPasswordsList();
} else if (last_deleted_exception_) { } else if (!last_deleted_exceptions_batch_.empty()) {
current_exceptions_.insert(current_exceptions_.begin(), current_exceptions_.insert(
std::move(*last_deleted_exception_)); current_exceptions_.begin(),
last_deleted_exception_ = base::nullopt; std::make_move_iterator(last_deleted_exceptions_batch_.begin()),
std::make_move_iterator(last_deleted_exceptions_batch_.end()));
last_deleted_exceptions_batch_.clear();
SendPasswordExceptionsList(); SendPasswordExceptionsList();
} }
} }
......
...@@ -25,8 +25,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate { ...@@ -25,8 +25,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
void ChangeSavedPassword(int id, void ChangeSavedPassword(int id,
base::string16 username, base::string16 username,
base::Optional<base::string16> password) override; base::Optional<base::string16> password) override;
void RemoveSavedPassword(int id) override; void RemoveSavedPasswords(const std::vector<int>& id) override;
void RemovePasswordException(int id) override; void RemovePasswordExceptions(const std::vector<int>& ids) override;
// Simplified version of undo logic, only use for testing. // Simplified version of undo logic, only use for testing.
void UndoRemoveSavedPasswordOrException() override; void UndoRemoveSavedPasswordOrException() override;
void RequestPlaintextPassword(int id, void RequestPlaintextPassword(int id,
...@@ -93,11 +93,15 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate { ...@@ -93,11 +93,15 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
// having to request them from |password_manager_presenter_| again. // having to request them from |password_manager_presenter_| again.
std::vector<api::passwords_private::PasswordUiEntry> current_entries_; std::vector<api::passwords_private::PasswordUiEntry> current_entries_;
std::vector<api::passwords_private::ExceptionEntry> current_exceptions_; std::vector<api::passwords_private::ExceptionEntry> current_exceptions_;
// Simplified version of a undo manager that only allows undoing and redoing
// the very last deletion. // Simplified version of an undo manager that only allows undoing and redoing
base::Optional<api::passwords_private::PasswordUiEntry> last_deleted_entry_; // the very last deletion. When the batches are *empty*, this means there is
base::Optional<api::passwords_private::ExceptionEntry> // no previous deletion to undo.
last_deleted_exception_; std::vector<api::passwords_private::PasswordUiEntry>
last_deleted_entries_batch_;
std::vector<api::passwords_private::ExceptionEntry>
last_deleted_exceptions_batch_;
base::Optional<base::string16> plaintext_password_ = base::Optional<base::string16> plaintext_password_ =
base::ASCIIToUTF16("plaintext"); base::ASCIIToUTF16("plaintext");
......
...@@ -330,19 +330,14 @@ void PasswordManagerPresenter::RemoveSavedPassword(size_t index) { ...@@ -330,19 +330,14 @@ void PasswordManagerPresenter::RemoveSavedPassword(size_t index) {
} }
} }
void PasswordManagerPresenter::RemoveSavedPassword(
const std::string& sort_key) {
if (TryRemovePasswordEntries(&password_map_, sort_key)) {
base::RecordAction(
base::UserMetricsAction("PasswordManager_RemoveSavedPassword"));
}
}
void PasswordManagerPresenter::RemoveSavedPasswords( void PasswordManagerPresenter::RemoveSavedPasswords(
const std::vector<std::string>& sort_keys) { const std::vector<std::string>& sort_keys) {
undo_manager_.StartGroupingActions(); undo_manager_.StartGroupingActions();
for (const std::string& sort_key : sort_keys) { for (const std::string& sort_key : sort_keys) {
RemoveSavedPassword(sort_key); if (TryRemovePasswordEntries(&password_map_, sort_key)) {
base::RecordAction(
base::UserMetricsAction("PasswordManager_RemoveSavedPassword"));
}
} }
undo_manager_.EndGroupingActions(); undo_manager_.EndGroupingActions();
} }
...@@ -354,19 +349,14 @@ void PasswordManagerPresenter::RemovePasswordException(size_t index) { ...@@ -354,19 +349,14 @@ void PasswordManagerPresenter::RemovePasswordException(size_t index) {
} }
} }
void PasswordManagerPresenter::RemovePasswordException(
const std::string& sort_key) {
if (TryRemovePasswordEntries(&exception_map_, sort_key)) {
base::RecordAction(
base::UserMetricsAction("PasswordManager_RemovePasswordException"));
}
}
void PasswordManagerPresenter::RemovePasswordExceptions( void PasswordManagerPresenter::RemovePasswordExceptions(
const std::vector<std::string>& sort_keys) { const std::vector<std::string>& sort_keys) {
undo_manager_.StartGroupingActions(); undo_manager_.StartGroupingActions();
for (const std::string& sort_key : sort_keys) { for (const std::string& sort_key : sort_keys) {
RemovePasswordException(sort_key); if (TryRemovePasswordEntries(&exception_map_, sort_key)) {
base::RecordAction(
base::UserMetricsAction("PasswordManager_RemovePasswordException"));
}
} }
undo_manager_.EndGroupingActions(); undo_manager_.EndGroupingActions();
} }
......
...@@ -80,7 +80,6 @@ class PasswordManagerPresenter ...@@ -80,7 +80,6 @@ class PasswordManagerPresenter
// TODO(https://crbug.com/778146): Unify these methods and the implementation // TODO(https://crbug.com/778146): Unify these methods and the implementation
// across Desktop and Android. // across Desktop and Android.
void RemoveSavedPassword(size_t index); void RemoveSavedPassword(size_t index);
void RemoveSavedPassword(const std::string& sort_key);
void RemoveSavedPasswords(const std::vector<std::string>& sort_keys); void RemoveSavedPasswords(const std::vector<std::string>& sort_keys);
// Removes the saved exception entries at |index|, or corresponding to // Removes the saved exception entries at |index|, or corresponding to
...@@ -88,7 +87,6 @@ class PasswordManagerPresenter ...@@ -88,7 +87,6 @@ class PasswordManagerPresenter
// TODO(https://crbug.com/778146): Unify these methods and the implementation // TODO(https://crbug.com/778146): Unify these methods and the implementation
// across Desktop and Android. // across Desktop and Android.
void RemovePasswordException(size_t index); void RemovePasswordException(size_t index);
void RemovePasswordException(const std::string& sort_key);
void RemovePasswordExceptions(const std::vector<std::string>& sort_keys); void RemovePasswordExceptions(const std::vector<std::string>& sort_keys);
// Undoes the last saved password or exception removal. // Undoes the last saved password or exception removal.
......
...@@ -443,8 +443,8 @@ TEST_F(PasswordManagerPresenterTest, TestPasswordRemovalAndUndo) { ...@@ -443,8 +443,8 @@ TEST_F(PasswordManagerPresenterTest, TestPasswordRemovalAndUndo) {
UnorderedElementsAre(Pair(kUsername, kPassword), UnorderedElementsAre(Pair(kUsername, kPassword),
Pair(kUsername2, kPassword2))); Pair(kUsername2, kPassword2)));
GetUIController().GetPasswordManagerPresenter()->RemoveSavedPassword( GetUIController().GetPasswordManagerPresenter()->RemoveSavedPasswords(
password_manager::CreateSortKey(password1)); {password_manager::CreateSortKey(password1)});
UpdatePasswordLists(); UpdatePasswordLists();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)), EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
UnorderedElementsAre(Pair(kUsername2, kPassword2))); UnorderedElementsAre(Pair(kUsername2, kPassword2)));
...@@ -463,8 +463,8 @@ TEST_F(PasswordManagerPresenterTest, TestExceptionRemovalAndUndo) { ...@@ -463,8 +463,8 @@ TEST_F(PasswordManagerPresenterTest, TestExceptionRemovalAndUndo) {
autofill::PasswordForm exception2 = AddPasswordException(GURL(kExampleOrg)); autofill::PasswordForm exception2 = AddPasswordException(GURL(kExampleOrg));
UpdatePasswordLists(); UpdatePasswordLists();
GetUIController().GetPasswordManagerPresenter()->RemovePasswordException( GetUIController().GetPasswordManagerPresenter()->RemovePasswordExceptions(
password_manager::CreateSortKey(exception1)); {password_manager::CreateSortKey(exception1)});
EXPECT_CALL(GetUIController(), SetPasswordExceptionList(UnorderedElementsAre( EXPECT_CALL(GetUIController(), SetPasswordExceptionList(UnorderedElementsAre(
HasOrigin(exception2.origin)))); HasOrigin(exception2.origin))));
UpdatePasswordLists(); UpdatePasswordLists();
......
...@@ -206,12 +206,24 @@ namespace passwordsPrivate { ...@@ -206,12 +206,24 @@ namespace passwordsPrivate {
// password entry being removed. // password entry being removed.
static void removeSavedPassword(long id); static void removeSavedPassword(long id);
// Removes the saved password exception corresponding to |exceptionUrl|. If // Removes the saved password corresponding to |ids|. If no saved password
// no exception with this URL exists, this function is a no-op. // exists for a certain id, that id is ignored. Undoing this operation via
// undoRemoveSavedPasswordOrException will restore all the removed passwords
// in the batch.
static void removeSavedPasswords(long[] ids);
// Removes the saved password exception corresponding to |id|. If
// no exception with this id exists, this function is a no-op.
// |id|: The id for the exception url entry being removed. // |id|: The id for the exception url entry being removed.
static void removePasswordException(long id); static void removePasswordException(long id);
// Undoes the last removal of a saved password or exception. // Removes the saved password exceptions corresponding to |ids|. If
// no exception exists for a certain id, that id is ignored. Undoing this
// operation via undoRemoveSavedPasswordOrException will restore all the
// removed exceptions in the batch.
static void removePasswordExceptions(long[] ids);
// Undoes the last removal of saved password(s) or exception(s).
static void undoRemoveSavedPasswordOrException(); static void undoRemoveSavedPasswordOrException();
// Returns the plaintext password corresponding to |id|. Note that on // Returns the plaintext password corresponding to |id|. Note that on
......
...@@ -56,6 +56,34 @@ var availableTests = [ ...@@ -56,6 +56,34 @@ var availableTests = [
chrome.passwordsPrivate.getSavedPasswordList(callback); chrome.passwordsPrivate.getSavedPasswordList(callback);
}, },
function removeAndUndoRemoveSavedPasswordsBatch() {
var numCalls = 0;
var numSavedPasswords;
var callback = function(savedPasswordsList) {
numCalls++;
if (numCalls == 1) {
numSavedPasswords = savedPasswordsList.length;
// There should be at least two passwords for this test to make sense.
chrome.test.assertTrue(numSavedPasswords >= 2);
chrome.passwordsPrivate.removeSavedPasswords(
Array(savedPasswordsList[0].id, savedPasswordsList[1].id));
} else if (numCalls == 2) {
chrome.test.assertEq(savedPasswordsList.length, numSavedPasswords - 2);
chrome.passwordsPrivate.undoRemoveSavedPasswordOrException();
} else if (numCalls == 3) {
chrome.test.assertEq(savedPasswordsList.length, numSavedPasswords);
chrome.test.succeed();
} else {
chrome.test.fail();
}
};
chrome.passwordsPrivate.onSavedPasswordsListChanged.addListener(callback);
chrome.passwordsPrivate.getSavedPasswordList(callback);
},
function removeAndUndoRemovePasswordException() { function removeAndUndoRemovePasswordException() {
var numCalls = 0; var numCalls = 0;
var numPasswordExceptions; var numPasswordExceptions;
...@@ -84,6 +112,36 @@ var availableTests = [ ...@@ -84,6 +112,36 @@ var availableTests = [
chrome.passwordsPrivate.getPasswordExceptionList(callback); chrome.passwordsPrivate.getPasswordExceptionList(callback);
}, },
function removeAndUndoRemovePasswordExceptionsBatch() {
var numCalls = 0;
var numPasswordExceptions;
var callback = function(passwordExceptionsList) {
numCalls++;
if (numCalls == 1) {
numPasswordExceptions = passwordExceptionsList.length;
// There should be at least two exceptions for this test to make sense.
chrome.test.assertTrue(numPasswordExceptions >= 2);
chrome.passwordsPrivate.removePasswordExceptions(
Array(passwordExceptionsList[0].id, passwordExceptionsList[1].id));
} else if (numCalls == 2) {
chrome.test.assertEq(
passwordExceptionsList.length, numPasswordExceptions - 2);
chrome.passwordsPrivate.undoRemoveSavedPasswordOrException();
} else if (numCalls == 3) {
chrome.test.assertEq(
passwordExceptionsList.length, numPasswordExceptions);
chrome.test.succeed();
} else {
chrome.test.fail();
}
};
chrome.passwordsPrivate.onPasswordExceptionsListChanged.addListener(
callback);
chrome.passwordsPrivate.getPasswordExceptionList(callback);
},
function requestPlaintextPassword() { function requestPlaintextPassword() {
chrome.passwordsPrivate.requestPlaintextPassword( chrome.passwordsPrivate.requestPlaintextPassword(
0, chrome.passwordsPrivate.PlaintextReason.VIEW, password => { 0, chrome.passwordsPrivate.PlaintextReason.VIEW, password => {
......
...@@ -1536,6 +1536,8 @@ enum HistogramValue { ...@@ -1536,6 +1536,8 @@ enum HistogramValue {
TERMINALPRIVATE_OPENWINDOW = 1473, TERMINALPRIVATE_OPENWINDOW = 1473,
AUTOTESTPRIVATE_SETPLUGINVMPOLICY = 1474, AUTOTESTPRIVATE_SETPLUGINVMPOLICY = 1474,
AUTOTESTPRIVATE_SHOWPLUGINVMINSTALLER = 1475, AUTOTESTPRIVATE_SHOWPLUGINVMINSTALLER = 1475,
PASSWORDSPRIVATE_REMOVESAVEDPASSWORDS = 1476,
PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS = 1477,
// Last entry: Add new entries above, then run: // Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py // python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -145,12 +145,26 @@ chrome.passwordsPrivate.changeSavedPassword = function( ...@@ -145,12 +145,26 @@ chrome.passwordsPrivate.changeSavedPassword = function(
chrome.passwordsPrivate.removeSavedPassword = function(id) {}; chrome.passwordsPrivate.removeSavedPassword = function(id) {};
/** /**
* Removes the saved password exception corresponding to |exceptionUrl|. If no * Removes the saved passwords corresponding to |ids|. If no saved password
* exception with this URL exists, this function is a no-op. * exists for a certain id, that id is ignored.
* @param {Array<number>} ids The ids for the password entries being removed.
*/
chrome.passwordsPrivate.removeSavedPasswords = function(ids) {};
/**
* Removes the saved password exception corresponding to |id|. If no
* exception with this id exists, this function is a no-op.
* @param {number} id The id for the exception url entry being removed. * @param {number} id The id for the exception url entry being removed.
*/ */
chrome.passwordsPrivate.removePasswordException = function(id) {}; chrome.passwordsPrivate.removePasswordException = function(id) {};
/**
* Removes the saved password exceptions corresponding to |ids|. If no
* exception exists for a certain id, that id is ignored.
* @param {Array<number>} ids The ids for the exception entries being removed.
*/
chrome.passwordsPrivate.removePasswordExceptions = function(ids) {};
/** /**
* Undoes the last removal of a saved password or exception. * Undoes the last removal of a saved password or exception.
*/ */
......
...@@ -23002,6 +23002,8 @@ Called by update_extension_histograms.py.--> ...@@ -23002,6 +23002,8 @@ Called by update_extension_histograms.py.-->
<int value="1473" label="TERMINALPRIVATE_OPENWINDOW"/> <int value="1473" label="TERMINALPRIVATE_OPENWINDOW"/>
<int value="1474" label="AUTOTESTPRIVATE_SETPLUGINVMPOLICY"/> <int value="1474" label="AUTOTESTPRIVATE_SETPLUGINVMPOLICY"/>
<int value="1475" label="AUTOTESTPRIVATE_SHOWPLUGINVMINSTALLER"/> <int value="1475" label="AUTOTESTPRIVATE_SHOWPLUGINVMINSTALLER"/>
<int value="1476" label="PASSWORDSPRIVATE_REMOVESAVEDPASSWORDS"/>
<int value="1477" label="PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS"/>
</enum> </enum>
<enum name="ExtensionIconState"> <enum name="ExtensionIconState">
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