[go: nahoru, domu]

blob: e661c85bee25d17c4a70e327cea738970df88163 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/settings/password/password_settings_app_interface.h"
#import <MaterialComponents/MaterialSnackbar.h>
#import "base/apple/foundation_util.h"
#import "base/strings/stringprintf.h"
#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "components/keyed_service/core/service_access_type.h"
#import "components/password_manager/core/browser/password_form.h"
#import "components/password_manager/core/browser/password_store_consumer.h"
#import "components/password_manager/core/browser/password_store_interface.h"
#import "components/password_manager/core/common/password_manager_features.h"
#import "components/password_manager/core/common/password_manager_pref_names.h"
#import "components/password_manager/ios/fake_bulk_leak_check_service.h"
#import "components/prefs/pref_service.h"
#import "ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h"
#import "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
#import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/sync/sync_service_factory.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/mock_reauthentication_module.h"
#import "ios/chrome/test/app/password_test_util.h"
#import "url/gurl.h"
#import "url/origin.h"
using chrome_test_util::
SetUpAndReturnMockReauthenticationModuleForPasswordManager;
using password_manager::FakeBulkLeakCheckService;
using password_manager::PasswordForm;
namespace {
scoped_refptr<password_manager::PasswordStoreInterface> GetPasswordStore() {
// ServiceAccessType governs behaviour in Incognito: only modifications with
// EXPLICIT_ACCESS, which correspond to user's explicit gesture, succeed.
// This test does not deal with Incognito, and should not run in Incognito
// context. Therefore IMPLICIT_ACCESS is used to let the test fail if in
// Incognito context.
return IOSChromePasswordStoreFactory::GetForBrowserState(
chrome_test_util::GetOriginalBrowserState(),
ServiceAccessType::IMPLICIT_ACCESS);
}
// This class is used to obtain results from the PasswordStore and hence both
// check the success of store updates and ensure that store has finished
// processing.
class FakeStoreConsumer : public password_manager::PasswordStoreConsumer {
public:
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<password_manager::PasswordForm>> obtained)
override {
obtained_ = std::move(obtained);
}
bool FetchStoreResults() {
results_.clear();
ResetObtained();
GetPasswordStore()->GetAllLogins(weak_ptr_factory_.GetWeakPtr());
bool responded =
base::test::ios::WaitUntilConditionOrTimeout(base::Seconds(2), ^bool {
return !AreObtainedReset();
});
if (responded) {
AppendObtainedToResults();
}
return responded;
}
const std::vector<password_manager::PasswordForm>& GetStoreResults() {
return results_;
}
private:
// Puts `obtained_` in a known state not corresponding to any PasswordStore
// state.
void ResetObtained() {
obtained_.clear();
obtained_.emplace_back(nullptr);
}
// Returns true if `obtained_` are in the reset state.
bool AreObtainedReset() { return obtained_.size() == 1 && !obtained_[0]; }
void AppendObtainedToResults() {
for (const auto& source : obtained_) {
results_.emplace_back(*source);
}
ResetObtained();
}
// Temporary cache of obtained store results.
std::vector<std::unique_ptr<password_manager::PasswordForm>> obtained_;
// Combination of fillable and blocked credentials from the store.
std::vector<password_manager::PasswordForm> results_;
base::WeakPtrFactory<FakeStoreConsumer> weak_ptr_factory_{this};
};
// Saves `form` to the password store and waits until the async processing is
// done.
bool SaveToPasswordStore(const PasswordForm& form) {
GetPasswordStore()->AddLogin(form);
// When we retrieve the form from the store, `in_store` should be set.
password_manager::PasswordForm expected_form = form;
expected_form.in_store = password_manager::PasswordForm::Store::kProfileStore;
// Check the result and ensure PasswordStore processed this.
FakeStoreConsumer consumer;
if (!consumer.FetchStoreResults()) {
return false;
}
for (const auto& result : consumer.GetStoreResults()) {
if (result == expected_form)
return true;
}
return false;
}
// Creates a PasswordForm with `index` being part of the username, password,
// origin and realm.
PasswordForm CreateSampleFormWithIndex(int index) {
PasswordForm form;
form.username_value =
base::ASCIIToUTF16(base::StringPrintf("concrete username %02d", index));
form.password_value =
base::ASCIIToUTF16(base::StringPrintf("concrete password %02d", index));
form.url = GURL(base::StringPrintf("https://www%02d.example.com", index));
form.signon_realm = form.url.spec();
return form;
}
bool ClearPasswordStore() {
GetPasswordStore()->RemoveLoginsCreatedBetween(base::Time(), base::Time(),
base::DoNothing());
FakeStoreConsumer consumer;
if (!consumer.FetchStoreResults()) {
return false;
}
return consumer.GetStoreResults().empty();
}
} // namespace
@implementation PasswordSettingsAppInterface
static std::unique_ptr<ScopedPasswordSettingsReauthModuleOverride>
_scopedReauthOverride;
// Helper for accessing the scoped override's module.
+ (MockReauthenticationModule*)mockModule {
DCHECK(_scopedReauthOverride);
return base::apple::ObjCCastStrict<MockReauthenticationModule>(
_scopedReauthOverride->module);
}
+ (void)setUpMockReauthenticationModule {
_scopedReauthOverride =
SetUpAndReturnMockReauthenticationModuleForPasswordManager();
}
+ (void)removeMockReauthenticationModule {
_scopedReauthOverride = nullptr;
}
+ (void)mockReauthenticationModuleExpectedResult:
(ReauthenticationResult)expectedResult {
[self mockModule].expectedResult = expectedResult;
}
+ (void)mockReauthenticationModuleCanAttempt:(BOOL)canAttempt {
DCHECK(_scopedReauthOverride);
[self mockModule].canAttempt = canAttempt;
}
+ (void)mockReauthenticationModuleShouldReturnSynchronously:(BOOL)returnSync {
[self mockModule].shouldReturnSynchronously = returnSync;
}
+ (void)mockReauthenticationModuleReturnMockedResult {
[[self mockModule] returnMockedReathenticationResult];
}
+ (void)dismissSnackBar {
[MDCSnackbarManager.defaultManager
dismissAndCallCompletionBlocksWithCategory:@"PasswordsSnackbarCategory"];
}
+ (void)saveExamplePasswordWithCount:(NSInteger)count {
for (int i = 1; i <= count; ++i) {
GetPasswordStore()->AddLogin(CreateSampleFormWithIndex(i));
}
}
+ (BOOL)saveExamplePassword:(NSString*)password
username:(NSString*)username
origin:(NSString*)origin {
PasswordForm example;
example.username_value = base::SysNSStringToUTF16(username);
example.password_value = base::SysNSStringToUTF16(password);
example.url = GURL(base::SysNSStringToUTF16(origin));
example.signon_realm = example.url.spec();
return SaveToPasswordStore(example);
}
+ (BOOL)saveExampleNote:(NSString*)note
password:(NSString*)password
username:(NSString*)username
origin:(NSString*)origin {
PasswordForm example;
example.username_value = base::SysNSStringToUTF16(username);
example.password_value = base::SysNSStringToUTF16(password);
example.url = GURL(base::SysNSStringToUTF16(origin));
example.signon_realm = example.url.spec();
example.notes = {password_manager::PasswordNote(
base::SysNSStringToUTF16(note), base::Time::Now())};
return SaveToPasswordStore(example);
}
+ (BOOL)saveCompromisedPassword:(NSString*)password
username:(NSString*)username
origin:(NSString*)origin {
PasswordForm example;
example.username_value = base::SysNSStringToUTF16(username);
example.password_value = base::SysNSStringToUTF16(password);
example.url = GURL(base::SysNSStringToUTF16(origin));
example.signon_realm = example.url.spec();
example.password_issues.insert({password_manager::InsecureType::kLeaked,
password_manager::InsecurityMetadata()});
return SaveToPasswordStore(example);
}
+ (BOOL)saveMutedCompromisedPassword:(NSString*)password
username:(NSString*)userName
origin:(NSString*)origin {
PasswordForm example;
example.username_value = base::SysNSStringToUTF16(userName);
example.password_value = base::SysNSStringToUTF16(password);
example.url = GURL(base::SysNSStringToUTF16(origin));
example.signon_realm = example.url.spec();
example.password_issues.insert(
{password_manager::InsecureType::kLeaked,
password_manager::InsecurityMetadata(
base::Time::Now(), password_manager::IsMuted(true),
password_manager::TriggerBackendNotification(false))});
return SaveToPasswordStore(example);
}
+ (BOOL)saveExampleBlockedOrigin:(NSString*)origin {
PasswordForm example;
example.url = GURL(base::SysNSStringToUTF16(origin));
example.blocked_by_user = true;
example.signon_realm = example.url.spec();
return SaveToPasswordStore(example);
}
+ (BOOL)saveExampleFederatedOrigin:(NSString*)federatedOrigin
username:(NSString*)username
origin:(NSString*)origin {
PasswordForm federated;
federated.username_value = base::SysNSStringToUTF16(username);
federated.url = GURL(base::SysNSStringToUTF16(origin));
federated.signon_realm = federated.url.spec();
federated.federation_origin =
url::Origin::Create(GURL(base::SysNSStringToUTF16(federatedOrigin)));
return SaveToPasswordStore(federated);
}
+ (NSInteger)passwordStoreResultsCount {
FakeStoreConsumer consumer;
if (!consumer.FetchStoreResults()) {
return -1;
}
return consumer.GetStoreResults().size();
}
+ (BOOL)clearPasswordStore {
return ClearPasswordStore();
}
+ (BOOL)isCredentialsServiceEnabled {
ChromeBrowserState* browserState =
chrome_test_util::GetOriginalBrowserState();
return browserState->GetPrefs()->GetBoolean(
password_manager::prefs::kCredentialsEnableService);
}
+ (void)setFakeBulkLeakCheckBufferedState:
(password_manager::BulkLeakCheckServiceInterface::State)state {
FakeBulkLeakCheckService* fakeBulkLeakCheckService =
static_cast<FakeBulkLeakCheckService*>(
IOSChromeBulkLeakCheckServiceFactory::GetForBrowserState(
chrome_test_util::GetOriginalBrowserState()));
fakeBulkLeakCheckService->SetBufferedState(state);
}
+ (BOOL)isPasswordCheckupEnabled {
return password_manager::features::IsPasswordCheckupEnabled();
}
@end