Commit b9a4429e authored by Scott Wu's avatar Scott Wu Committed by Commit Bot

Move password suggestion logic into components.

Bug: 865114
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: Ibf5ee92330172532dff87f9752d301a134ec49fc
Reviewed-on: https://chromium-review.googlesource.com/c/1264455Reviewed-by: default avatarJohn Wu <jzw@chromium.org>
Reviewed-by: default avatarVadym Doroshenko <dvadym@chromium.org>
Reviewed-by: default avatarHiroshi Ichikawa <ichikawa@chromium.org>
Commit-Queue: Scott Wu <scottwu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#599165}
parent d84303e4
...@@ -25,6 +25,8 @@ component("ios") { ...@@ -25,6 +25,8 @@ component("ios") {
"js_password_manager.mm", "js_password_manager.mm",
"password_controller_helper.h", "password_controller_helper.h",
"password_controller_helper.mm", "password_controller_helper.mm",
"password_suggestion_helper.h",
"password_suggestion_helper.mm",
] ]
} }
......
// 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 COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_SUGGESTION_HELPER_H_
#define COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_SUGGESTION_HELPER_H_
#import <Foundation/Foundation.h>
#include <memory>
#import "components/autofill/ios/browser/form_suggestion_provider.h"
NS_ASSUME_NONNULL_BEGIN
@class FormSuggestion;
@class PasswordSuggestionHelper;
namespace autofill {
struct PasswordFormFillData;
} // namespace autofill
namespace password_manager {
struct FillData;
} // namespace password_manager
namespace web {
class WebState;
} // namespace web
// A protocol implemented by a delegate of PasswordSuggestionHelper.
@protocol PasswordSuggestionHelperDelegate<NSObject>
// Called when form extraction is required for checking suggestion availability.
// The caller must trigger the form extraction in this method.
- (void)suggestionHelperShouldTriggerFormExtraction:
(PasswordSuggestionHelper*)suggestionHelper;
@end
// Provides common logic of password autofill suggestions for both ios/chrome
// and ios/web_view.
@interface PasswordSuggestionHelper : NSObject
// Creates an instance with the given delegate.
- (instancetype)initWithDelegate:(id<PasswordSuggestionHelperDelegate>)delegate
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// Retrieves suggestions as username and realm pairs
// (defined in |password_manager::UsernameAndRealm|) and converts
// them into objective C representations. In the returned |FormSuggestion|
// items, |value| field will be the username and |displayDescription| will be
// the realm.
- (NSArray<FormSuggestion*>*)
retrieveSuggestionsWithFormName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
fieldType:(NSString*)fieldType;
// Checks if suggestions are available for the field.
// |completion| will be called when the check is completed, with boolean
// parameter indicating whether suggestions are available or not.
// See //components/autofill/ios/form_util/form_activity_params.h for definition
// of other parameters.
- (void)checkIfSuggestionsAvailableForForm:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
type:(NSString*)type
frameID:(NSString*)frameID
isMainFrame:(BOOL)isMainFrame
webState:(web::WebState*)webState
completionHandler:
(SuggestionsAvailableCompletion)completion;
// Retrieves password form fill data for |username| for use in
// |PasswordControllerHelper|'s
// -fillPasswordFormWithFillData:completionHandler:.
- (std::unique_ptr<password_manager::FillData>)getFillDataForUsername:
(NSString*)username;
// The following methods should be called to maintain the correct state along
// with password forms.
// Resets fill data, callbacks and state flags for new page. This method should
// be called in password controller's -webState:didLoadPageWithSuccess:.
- (void)resetForNewPage;
// Prepares fill data with given password form data. Triggers callback for
// -checkIfSuggestionsAvailableForForm... if needed.
// This method should be called in password controller's
// -fillPasswordForm:completionHandler:.
- (void)processWithPasswordFormFillData:
(const autofill::PasswordFormFillData&)formData;
// Processes field for which no saved credentials are available.
// Triggers callback for -checkIfSuggestionsAvailableForForm... if needed.
// This method should be called in password controller's
// -onNoSavedCredentials.
- (void)processWithNoSavedCredentials;
// Updates the state for password form extraction state.
// This method should be called in password controller's
// -didFinishPasswordFormExtraction:, when the extracted forms are not empty.
- (void)updateStateOnPasswordFormExtracted;
@end
NS_ASSUME_NONNULL_END
#endif // COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_SUGGESTION_HELPER_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 "components/password_manager/ios/password_suggestion_helper.h"
#include "base/strings/sys_string_conversions.h"
#include "components/autofill/core/common/form_data.h"
#import "components/autofill/ios/browser/form_suggestion.h"
#include "components/password_manager/ios/account_select_fill_data.h"
#include "ios/web/public/web_state/web_frame.h"
#include "ios/web/public/web_state/web_frame_util.h"
#import "ios/web/public/web_state/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using autofill::FormData;
using autofill::PasswordFormFillData;
using base::SysNSStringToUTF16;
using base::SysNSStringToUTF8;
using base::SysUTF16ToNSString;
using base::SysUTF8ToNSString;
using password_manager::AccountSelectFillData;
using password_manager::FillData;
typedef void (^PasswordSuggestionsAvailableCompletion)(
const password_manager::AccountSelectFillData* __nullable);
namespace {
NSString* const kPasswordFieldType = @"password";
} // namespace
@interface PasswordSuggestionHelper ()
// Delegate to receive callbacks.
@property(nonatomic, weak, readonly) id<PasswordSuggestionHelperDelegate>
delegate;
@end
@implementation PasswordSuggestionHelper {
// The C++ interface to cache and retrieve password suggestions.
AccountSelectFillData _fillData;
// YES indicates that extracted password form has been sent to the password
// manager.
BOOL _sentPasswordFormToPasswordManager;
// The completion to inform the caller of -checkIfSuggestionsAvailableForForm:
// that suggestions are available for a given form and field.
PasswordSuggestionsAvailableCompletion _suggestionsAvailableCompletion;
}
@synthesize delegate = _delegate;
- (instancetype)initWithDelegate:
(id<PasswordSuggestionHelperDelegate>)delegate {
self = [super init];
if (self) {
_sentPasswordFormToPasswordManager = NO;
_delegate = delegate;
}
return self;
}
#pragma mark - Public methods
- (NSArray<FormSuggestion*>*)
retrieveSuggestionsWithFormName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
fieldType:(NSString*)fieldType {
base::string16 utfFormName = SysNSStringToUTF16(formName);
base::string16 utfFieldIdentifier = SysNSStringToUTF16(fieldIdentifier);
BOOL isPasswordField = [fieldType isEqual:kPasswordFieldType];
NSMutableArray<FormSuggestion*>* results = [NSMutableArray array];
if (_fillData.IsSuggestionsAvailable(utfFormName, utfFieldIdentifier,
isPasswordField)) {
std::vector<password_manager::UsernameAndRealm> usernameAndRealms =
_fillData.RetrieveSuggestions(utfFormName, utfFieldIdentifier,
isPasswordField);
for (const auto& usernameAndRealm : usernameAndRealms) {
NSString* username = SysUTF16ToNSString(usernameAndRealm.username);
NSString* realm = usernameAndRealm.realm.empty()
? nil
: SysUTF8ToNSString(usernameAndRealm.realm);
[results addObject:[FormSuggestion suggestionWithValue:username
displayDescription:realm
icon:nil
identifier:0]];
}
}
return [results copy];
}
- (void)checkIfSuggestionsAvailableForForm:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
type:(NSString*)type
frameID:(NSString*)frameID
isMainFrame:(BOOL)isMainFrame
webState:(web::WebState*)webState
completionHandler:
(SuggestionsAvailableCompletion)completion {
// When password controller's -processWithPasswordFormFillData: is already
// called, |completion| will be called immediately and |triggerFormExtraction|
// will be skipped.
// Otherwise, -suggestionHelperShouldTriggerFormExtraction: will be called
// and |completion| will not be called until
// -processWithPasswordFormFillData: is called.
// For unsupported form, |completion| will be called immediately and
// -suggestionHelperShouldTriggerFormExtraction: will be skipped.
if (!isMainFrame) {
web::WebFrame* frame =
web::GetWebFrameWithId(webState, SysNSStringToUTF8(frameID));
if (!frame || webState->GetLastCommittedURL().GetOrigin() !=
frame->GetSecurityOrigin()) {
// Passwords is only supported on main frame and iframes with the same
// origin.
completion(NO);
}
}
if (!_sentPasswordFormToPasswordManager && [type isEqual:@"focus"]) {
// Save the callback until fill data is ready.
_suggestionsAvailableCompletion = ^(const AccountSelectFillData* fillData) {
completion(!fillData ? NO
: fillData->IsSuggestionsAvailable(
SysNSStringToUTF16(formName),
SysNSStringToUTF16(fieldIdentifier), false));
};
// Form extraction is required for this check.
[self.delegate suggestionHelperShouldTriggerFormExtraction:self];
return;
}
completion(_fillData.IsSuggestionsAvailable(
SysNSStringToUTF16(formName), SysNSStringToUTF16(fieldIdentifier),
false));
}
- (std::unique_ptr<password_manager::FillData>)getFillDataForUsername:
(NSString*)username {
return _fillData.GetFillData(SysNSStringToUTF16(username));
}
- (void)resetForNewPage {
_fillData.Reset();
_sentPasswordFormToPasswordManager = NO;
_suggestionsAvailableCompletion = nil;
}
- (void)processWithPasswordFormFillData:(const PasswordFormFillData&)formData {
_fillData.Add(formData);
if (_suggestionsAvailableCompletion) {
_suggestionsAvailableCompletion(&_fillData);
_suggestionsAvailableCompletion = nil;
}
}
- (void)processWithNoSavedCredentials {
if (_suggestionsAvailableCompletion) {
_suggestionsAvailableCompletion(nullptr);
}
_suggestionsAvailableCompletion = nil;
}
- (void)updateStateOnPasswordFormExtracted {
_sentPasswordFormToPasswordManager = YES;
}
@end
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