0

[no-behavior-changed] Add extension API to allow password migration

No behavior is changed. This CL introduces a new extension API to allow
Password Settings to move a user password from the device to their
account. The API is not called yet and is left with NOTIMPLEMENTED();
Future CLs will: a) add the relevant logic to PasswordManagerPresenter,
the same way it is done for most passwords JS APIs; b) call the API from
the new "Passwords on this device" page (crrev.com/c/2228159).

As a note, the method in the PasswordsPrivateDelegate takes the sender
web contents because it will be needed to retrieve the password
manager client.

Bug: 1090372
Change-Id: I76859af0ab22fa074a802d785ad7c9a0fc3fa912
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2232371
Reviewed-by: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: dpapad <dpapad@chromium.org>
Commit-Queue: Victor Vianna <victorvianna@google.com>
Cr-Commit-Position: refs/heads/master@{#777316}
This commit is contained in:
Victor Hugo Vianna Silva
2020-06-11 11:33:10 +00:00
committed by Commit Bot
parent 79a6108a6a
commit aa498efcd6
13 changed files with 92 additions and 0 deletions

@@ -194,6 +194,16 @@ void PasswordsPrivateGetPasswordExceptionListFunction::GotList(
entries)));
}
// PasswordsPrivateMovePasswordToAccountFunction
ResponseAction PasswordsPrivateMovePasswordToAccountFunction::Run() {
auto parameters =
api::passwords_private::MovePasswordToAccount::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters);
GetDelegate(browser_context())
->MovePasswordToAccount(parameters->id, GetSenderWebContents());
return RespondNow(NoArguments());
}
// PasswordsPrivateImportPasswordsFunction
ResponseAction PasswordsPrivateImportPasswordsFunction::Run() {
GetDelegate(browser_context())->ImportPasswords(GetSenderWebContents());

@@ -156,6 +156,18 @@ class PasswordsPrivateGetPasswordExceptionListFunction
void GotList(const PasswordsPrivateDelegate::ExceptionEntries& entries);
};
class PasswordsPrivateMovePasswordToAccountFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.movePasswordToAccount",
PASSWORDSPRIVATE_MOVEPASSWORDTOACCOUNT)
protected:
~PasswordsPrivateMovePasswordToAccountFunction() override = default;
// ExtensionFunction overrides.
ResponseAction Run() override;
};
class PasswordsPrivateImportPasswordsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.importPasswords",

@@ -108,6 +108,10 @@ class PasswordsPrivateApiTest : public ExtensionApiTest {
s_test_delegate_->AddCompromisedCredential(id);
}
base::Optional<int> last_moved_password() const {
return s_test_delegate_->last_moved_password();
}
private:
TestPasswordsPrivateDelegate* s_test_delegate_ = nullptr;
@@ -271,4 +275,10 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPasswordCheckStatus) {
EXPECT_TRUE(RunPasswordsSubtest("getPasswordCheckStatus")) << message_;
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, MovePasswordToAccount) {
EXPECT_FALSE(last_moved_password().has_value());
EXPECT_TRUE(RunPasswordsSubtest("movePasswordToAccount")) << message_;
EXPECT_EQ(42, last_moved_password());
}
} // namespace extensions

@@ -90,6 +90,15 @@ class PasswordsPrivateDelegate : public KeyedService {
PlaintextPasswordCallback callback,
content::WebContents* web_contents) = 0;
// Moves a password currently stored on the device to being stored in the
// signed-in, non-syncing Google Account. The result is a no-op if any of
// these is true: |id| is invalid; |id| corresponds to a password already
// stored in the account; the user is not in Passwords Account Storage mode
// (kEnablePasswordsAccountStorage enabled, signed-in, not syncing and
// opted-in to the feature).
virtual void MovePasswordToAccount(int id,
content::WebContents* web_contents) = 0;
// Trigger the password import procedure, allowing the user to select a file
// containing passwords to import.
virtual void ImportPasswords(content::WebContents* web_contents) = 0;

@@ -403,6 +403,12 @@ void PasswordsPrivateDelegateImpl::SetPasswordExceptionList(
get_password_exception_list_callbacks_.clear();
}
void PasswordsPrivateDelegateImpl::MovePasswordToAccount(
int id,
content::WebContents* web_contents) {
NOTIMPLEMENTED();
}
void PasswordsPrivateDelegateImpl::ImportPasswords(
content::WebContents* web_contents) {
password_manager_porter_->set_web_contents(web_contents);

@@ -60,6 +60,8 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
api::passwords_private::PlaintextReason reason,
PlaintextPasswordCallback callback,
content::WebContents* web_contents) override;
void MovePasswordToAccount(int id,
content::WebContents* web_contents) override;
void ImportPasswords(content::WebContents* web_contents) override;
void ExportPasswords(base::OnceCallback<void(const std::string&)> accepted,
content::WebContents* web_contents) override;

@@ -136,6 +136,12 @@ void TestPasswordsPrivateDelegate::RequestPlaintextPassword(
std::move(callback).Run(plaintext_password_);
}
void TestPasswordsPrivateDelegate::MovePasswordToAccount(
int id,
content::WebContents* web_contents) {
last_moved_password_ = id;
}
void TestPasswordsPrivateDelegate::ImportPasswords(
content::WebContents* web_contents) {
// The testing of password importing itself should be handled via

@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_TEST_PASSWORDS_PRIVATE_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_TEST_PASSWORDS_PRIVATE_DELEGATE_H_
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
#include "chrome/browser/profiles/profile.h"
@@ -33,6 +34,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
api::passwords_private::PlaintextReason reason,
PlaintextPasswordCallback callback,
content::WebContents* web_contents) override;
void MovePasswordToAccount(int id,
content::WebContents* web_contents) override;
void ImportPasswords(content::WebContents* web_contents) override;
void ExportPasswords(base::OnceCallback<void(const std::string&)> callback,
content::WebContents* web_contents) override;
@@ -84,6 +87,10 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
start_password_check_state_ = state;
}
base::Optional<int> last_moved_password() const {
return last_moved_password_;
}
private:
void SendSavedPasswordsList();
void SendPasswordExceptionsList();
@@ -122,6 +129,9 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
bool stop_password_check_triggered_ = false;
password_manager::BulkLeakCheckService::State start_password_check_state_ =
password_manager::BulkLeakCheckService::State::kRunning;
// Records the id of the last password that was moved.
base::Optional<int> last_moved_password_ = base::nullopt;
};
} // namespace extensions

@@ -252,6 +252,15 @@ namespace passwordsPrivate {
// |callback|: Called with the list of password exceptions.
static void getPasswordExceptionList(ExceptionListCallback callback);
// Moves a password currently stored on the device to being stored in the
// signed-in, non-syncing Google Account. The result is a no-op if any of
// these is true: |id| is invalid; |id| corresponds to a password already
// stored in the account; the user is not in Passwords Account Storage mode
// (kEnablePasswordsAccountStorage enabled, signed-in, not syncing and
// opted-in to the feature).
// |id|: The id for the password entry being moved.
static void movePasswordToAccount(long id);
// Triggers the Password Manager password import functionality.
static void importPasswords();

@@ -463,6 +463,11 @@ var availableTests = [
chrome.test.succeed();
});
},
function movePasswordToAccount() {
chrome.passwordsPrivate.movePasswordToAccount(42);
chrome.test.succeed();
}
];
var testToRun = window.location.search.substring(1);

@@ -1540,6 +1540,7 @@ enum HistogramValue {
PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS = 1477,
AUTOTESTPRIVATE_WAITFORAMBIENTPHOTOANIMATION = 1478,
INPUT_IME_SETASSISTIVEWINDOWPROPERTIES = 1479,
PASSWORDSPRIVATE_MOVEPASSWORDTOACCOUNT = 1480,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY

@@ -199,6 +199,17 @@ chrome.passwordsPrivate.getSavedPasswordList = function(callback) {};
*/
chrome.passwordsPrivate.getPasswordExceptionList = function(callback) {};
/**
* Moves a password currently stored on the device to being stored in the
* signed-in, non-syncing Google Account. The result is a no-op if any of
* these is true: |id| is invalid; |id| corresponds to a password already
* stored in the account; the user is not in Passwords Account Storage mode
* (kEnablePasswordsAccountStorage enabled, signed-in, not syncing and
* opted-in to the feature).
* @param {number} id The id for the password entry being moved.
*/
chrome.passwordsPrivate.movePasswordToAccount = function(id) {};
/**
* Triggers the Password Manager password import functionality.
*/

@@ -23230,6 +23230,7 @@ Called by update_extension_histograms.py.-->
<int value="1477" label="PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS"/>
<int value="1478" label="AUTOTESTPRIVATE_WAITFORAMBIENTPHOTOANIMATION"/>
<int value="1479" label="INPUT_IME_SETASSISTIVEWINDOWPROPERTIES"/>
<int value="1480" label="PASSWORDSPRIVATE_MOVEPASSWORDTOACCOUNT"/>
</enum>
<enum name="ExtensionIconState">