Commit 9f078299 authored by Javier Ernesto Flores Robles's avatar Javier Ernesto Flores Robles Committed by Commit Bot

[iOS][MF] Adds password fetcher for manual fill

This object will be in charge to fetch the passwords for Manual Fill.
A Passwords Mediator will be the delegate and owner of it.

Bug: 845472
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I7e15656c4d9979aff5c86d79bab7a42e5161408b
Reviewed-on: https://chromium-review.googlesource.com/1148813Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578337}
parent c614c6ab
...@@ -8,12 +8,37 @@ source_set("manual_fill") { ...@@ -8,12 +8,37 @@ source_set("manual_fill") {
sources = [ sources = [
"accessory_provider.h", "accessory_provider.h",
"accessory_provider.mm", "accessory_provider.mm",
"passwords_fetcher.h",
"passwords_fetcher.mm",
] ]
deps = [ deps = [
"//base", "//base",
"//ios/chrome/browser/autofill", "//components/autofill/core/common:common",
"//components/keyed_service/core:core",
"//components/password_manager/core/browser:browser",
"//ios/chrome/browser/autofill:autofill_shared",
"//ios/chrome/browser/browser_state:browser_state",
"//ios/chrome/browser/passwords:passwords",
"//ios/chrome/browser/ui/autofill/manual_fill", "//ios/chrome/browser/ui/autofill/manual_fill",
] ]
libs = [ "UIKit.framework" ] libs = [ "UIKit.framework" ]
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
} }
source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
sources = [
"passwords_fetcher_unittest.mm",
]
deps = [
":manual_fill",
"//base/test:test_support",
"//components/autofill/core/common:common",
"//components/keyed_service/core:core",
"//components/password_manager/core/browser:test_support",
"//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/passwords:passwords",
"//testing/gtest:gtest",
]
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
#define IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
#import <Foundation/Foundation.h>
#include <memory>
#include <vector>
namespace autofill {
struct PasswordForm;
} // namespace autofill
namespace ios {
class ChromeBrowserState;
} // namespace ios
@class PasswordFetcher;
// Protocol to receive the passwords fetched asynchronously.
@protocol PasswordFetcherDelegate
// Saved passwords has been fetched or updated.
- (void)passwordFetcher:(PasswordFetcher*)passwordFetcher
didFetchPasswords:
(std::vector<std::unique_ptr<autofill::PasswordForm>>&)passwords;
@end
@interface PasswordFetcher : NSObject
// The designated initializer. |browserState| must not be nil.
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
delegate:(id<PasswordFetcherDelegate>)delegate
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_AUTOFILL_MANUAL_FILL_PASSWORDS_FETCHER_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
#include "components/autofill/core/common/password_form.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/password_list_sorter.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
#include "ios/chrome/browser/passwords/save_passwords_consumer.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface PasswordFetcher ()<SavePasswordsConsumerDelegate> {
// The interface for getting and manipulating a user's saved passwords.
scoped_refptr<password_manager::PasswordStore> _passwordStore;
// A helper object for passing data about saved passwords from a finished
// password store request to the SavePasswordsCollectionViewController.
std::unique_ptr<ios::SavePasswordsConsumer> _savedPasswordsConsumer;
// The list of the user's saved passwords.
std::vector<std::unique_ptr<autofill::PasswordForm>> _savedForms;
// The current Chrome browser state.
ios::ChromeBrowserState* _browserState;
}
// Delegate to send the fetchted passwords.
@property(nonatomic, weak) id<PasswordFetcherDelegate> delegate;
@end
@implementation PasswordFetcher
@synthesize delegate = _delegate;
#pragma mark - Initialization
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
delegate:(id<PasswordFetcherDelegate>)delegate {
DCHECK(browserState);
self = [super init];
if (self) {
_browserState = browserState;
_delegate = delegate;
_passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState(
_browserState, ServiceAccessType::EXPLICIT_ACCESS);
DCHECK(_passwordStore);
_savedPasswordsConsumer.reset(new ios::SavePasswordsConsumer(self));
_passwordStore->GetAutofillableLogins(_savedPasswordsConsumer.get());
}
return self;
}
#pragma mark - SavePasswordsConsumerDelegate
- (void)onGetPasswordStoreResults:
(std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
for (auto it = result.begin(); it != result.end(); ++it) {
if (!(*it)->blacklisted_by_user)
_savedForms.push_back(std::move(*it));
}
password_manager::DuplicatesMap savedPasswordDuplicates;
password_manager::SortEntriesAndHideDuplicates(&_savedForms,
&savedPasswordDuplicates);
[self.delegate passwordFetcher:self didFetchPasswords:_savedForms];
}
@end
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
#import <Foundation/Foundation.h>
#include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "base/test/scoped_task_environment.h"
#include "components/autofill/core/common/password_form.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using base::test::ios::WaitUntilCondition;
// Test object conforming to PasswordFetcherDelegate used to verify the results
// from the password store.
@interface TestPasswordFetcherDelegate : NSObject<PasswordFetcherDelegate> {
// Ivar to store the results from the store.
std::vector<std::unique_ptr<autofill::PasswordForm>> _passwords;
}
// Returns the count of recieved passwords.
@property(nonatomic, readonly) size_t passwordNumber;
@end
@implementation TestPasswordFetcherDelegate
- (void)passwordFetcher:(PasswordFetcher*)passwordFetcher
didFetchPasswords:
(std::vector<std::unique_ptr<autofill::PasswordForm>>&)passwords {
_passwords = std::move(passwords);
}
- (size_t)passwordNumber {
return _passwords.size();
}
@end
namespace {
class PasswordFetcherTest : public PlatformTest {
protected:
PasswordFetcherTest() = default;
void SetUp() override {
PlatformTest::SetUp();
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = test_cbs_builder.Build();
IOSChromePasswordStoreFactory::GetInstance()->SetTestingFactory(
chrome_browser_state_.get(),
&password_manager::BuildPasswordStore<
web::BrowserState, password_manager::TestPasswordStore>);
}
password_manager::PasswordStore* GetPasswordStore() {
return IOSChromePasswordStoreFactory::GetForBrowserState(
chrome_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS)
.get();
}
// Creates and adds a saved password form.
void AddSavedForm1() {
auto form = std::make_unique<autofill::PasswordForm>();
form->origin = GURL("http://www.example.com/accounts/LoginAuth");
form->action = GURL("http://www.example.com/accounts/Login");
form->username_element = base::ASCIIToUTF16("Email");
form->username_value = base::ASCIIToUTF16("test@egmail.com");
form->password_element = base::ASCIIToUTF16("Passwd");
form->password_value = base::ASCIIToUTF16("test");
form->submit_element = base::ASCIIToUTF16("signIn");
form->signon_realm = "http://www.example.com/";
form->preferred = false;
form->scheme = autofill::PasswordForm::SCHEME_HTML;
form->blacklisted_by_user = false;
GetPasswordStore()->AddLogin(*std::move(form));
}
// Creates and adds a saved password form.
void AddSavedForm2() {
auto form = std::make_unique<autofill::PasswordForm>();
form->origin = GURL("http://www.example2.com/accounts/LoginAuth");
form->action = GURL("http://www.example2.com/accounts/Login");
form->username_element = base::ASCIIToUTF16("Email");
form->username_value = base::ASCIIToUTF16("test@egmail.com");
form->password_element = base::ASCIIToUTF16("Passwd");
form->password_value = base::ASCIIToUTF16("test");
form->submit_element = base::ASCIIToUTF16("signIn");
form->signon_realm = "http://www.example2.com/";
form->preferred = false;
form->scheme = autofill::PasswordForm::SCHEME_HTML;
form->blacklisted_by_user = false;
GetPasswordStore()->AddLogin(*std::move(form));
}
// Creates and adds a blacklisted site form to never offer to save
// user's password to those sites.
void AddBlacklistedForm() {
auto form = std::make_unique<autofill::PasswordForm>();
form->origin = GURL("http://www.secret.com/login");
form->action = GURL("http://www.secret.com/action");
form->username_element = base::ASCIIToUTF16("email");
form->username_value = base::ASCIIToUTF16("test@secret.com");
form->password_element = base::ASCIIToUTF16("password");
form->password_value = base::ASCIIToUTF16("cantsay");
form->submit_element = base::ASCIIToUTF16("signIn");
form->signon_realm = "http://www.secret.com/";
form->preferred = false;
form->scheme = autofill::PasswordForm::SCHEME_HTML;
form->blacklisted_by_user = true;
GetPasswordStore()->AddLogin(*std::move(form));
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
};
// Tests PasswordFetcher initialization.
TEST_F(PasswordFetcherTest, Initialization) {
PasswordFetcher* passwordFetcher =
[[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
delegate:nil];
EXPECT_TRUE(passwordFetcher);
}
// Tests PasswordFetcher returns 1 passwords.
TEST_F(PasswordFetcherTest, ReturnsPassword) {
AddSavedForm1();
TestPasswordFetcherDelegate* passwordFetcherDelegate =
[[TestPasswordFetcherDelegate alloc] init];
PasswordFetcher* passwordFetcher =
[[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
delegate:passwordFetcherDelegate];
WaitUntilCondition(
^bool {
return passwordFetcherDelegate.passwordNumber > 0;
},
true, base::TimeDelta::FromSeconds(1000));
EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
EXPECT_TRUE(passwordFetcher);
}
// Tests PasswordFetcher returns 2 passwords.
TEST_F(PasswordFetcherTest, ReturnsTwoPasswords) {
AddSavedForm1();
AddSavedForm2();
TestPasswordFetcherDelegate* passwordFetcherDelegate =
[[TestPasswordFetcherDelegate alloc] init];
PasswordFetcher* passwordFetcher =
[[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
delegate:passwordFetcherDelegate];
WaitUntilCondition(
^bool {
return passwordFetcherDelegate.passwordNumber > 0;
},
true, base::TimeDelta::FromSeconds(1000));
EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 2u);
EXPECT_TRUE(passwordFetcher);
}
// Tests PasswordFetcher ignores blacklisted passwords.
TEST_F(PasswordFetcherTest, IgnoresBlacklisted) {
AddSavedForm1();
AddBlacklistedForm();
TestPasswordFetcherDelegate* passwordFetcherDelegate =
[[TestPasswordFetcherDelegate alloc] init];
PasswordFetcher* passwordFetcher =
[[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
delegate:passwordFetcherDelegate];
WaitUntilCondition(
^bool {
return passwordFetcherDelegate.passwordNumber > 0;
},
true, base::TimeDelta::FromSeconds(1000));
EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
EXPECT_TRUE(passwordFetcher);
}
// Tests PasswordFetcher ignores duplicated passwords.
TEST_F(PasswordFetcherTest, IgnoresDuplicated) {
AddSavedForm1();
AddSavedForm1();
AddSavedForm1();
AddSavedForm1();
TestPasswordFetcherDelegate* passwordFetcherDelegate =
[[TestPasswordFetcherDelegate alloc] init];
PasswordFetcher* passwordFetcher =
[[PasswordFetcher alloc] initWithBrowserState:chrome_browser_state_.get()
delegate:passwordFetcherDelegate];
WaitUntilCondition(
^bool {
return passwordFetcherDelegate.passwordNumber > 0;
},
true, base::TimeDelta::FromSeconds(1000));
EXPECT_EQ(passwordFetcherDelegate.passwordNumber, 1u);
EXPECT_TRUE(passwordFetcher);
}
} // namespace
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
// Callback called when the async request launched from // Callback called when the async request launched from
// |getLoginsFromPasswordStore| finishes. // |getLoginsFromPasswordStore| finishes.
- (void)onGetPasswordStoreResults: - (void)onGetPasswordStoreResults:
(const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result; (std::vector<std::unique_ptr<autofill::PasswordForm>>&)result;
@end @end
......
...@@ -475,7 +475,7 @@ initWithActivityItems:(NSArray*)activityItems ...@@ -475,7 +475,7 @@ initWithActivityItems:(NSArray*)activityItems
#pragma mark - SavePasswordsConsumerDelegate #pragma mark - SavePasswordsConsumerDelegate
- (void)onGetPasswordStoreResults: - (void)onGetPasswordStoreResults:
(const std::vector<std::unique_ptr<autofill::PasswordForm>>&)result { (std::vector<std::unique_ptr<autofill::PasswordForm>>&)result {
for (auto it = result.begin(); it != result.end(); ++it) { for (auto it = result.begin(); it != result.end(); ++it) {
// PasswordForm is needed when user wants to delete the site/password. // PasswordForm is needed when user wants to delete the site/password.
auto form = std::make_unique<autofill::PasswordForm>(**it); auto form = std::make_unique<autofill::PasswordForm>(**it);
......
...@@ -141,6 +141,7 @@ test("ios_chrome_unittests") { ...@@ -141,6 +141,7 @@ test("ios_chrome_unittests") {
"//ios/chrome/browser:unit_tests", "//ios/chrome/browser:unit_tests",
"//ios/chrome/browser/app_launcher:unit_tests", "//ios/chrome/browser/app_launcher:unit_tests",
"//ios/chrome/browser/autofill:unit_tests", "//ios/chrome/browser/autofill:unit_tests",
"//ios/chrome/browser/autofill/manual_fill:unit_tests",
"//ios/chrome/browser/browser_state:unit_tests", "//ios/chrome/browser/browser_state:unit_tests",
"//ios/chrome/browser/browsing_data:unit_tests", "//ios/chrome/browser/browsing_data:unit_tests",
"//ios/chrome/browser/crash_report:unit_tests", "//ios/chrome/browser/crash_report:unit_tests",
......
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