password_form_helper.mm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "components/password_manager/ios/password_form_helper.h"
  5. #include <stddef.h>
  6. #include "base/bind.h"
  7. #include "base/metrics/histogram_functions.h"
  8. #include "base/metrics/histogram_macros.h"
  9. #include "base/strings/sys_string_conversions.h"
  10. #include "base/strings/utf_string_conversions.h"
  11. #include "base/values.h"
  12. #include "components/autofill/core/common/field_data_manager.h"
  13. #include "components/autofill/core/common/form_data.h"
  14. #include "components/autofill/core/common/password_form_fill_data.h"
  15. #include "components/autofill/ios/browser/autofill_util.h"
  16. #import "components/autofill/ios/form_util/form_util_java_script_feature.h"
  17. #include "components/autofill/ios/form_util/unique_id_data_tab_helper.h"
  18. #include "components/password_manager/ios/account_select_fill_data.h"
  19. #include "components/password_manager/ios/password_manager_ios_util.h"
  20. #import "components/password_manager/ios/password_manager_java_script_feature.h"
  21. #include "components/ukm/ios/ukm_url_recorder.h"
  22. #import "ios/web/public/js_messaging/web_frame.h"
  23. #import "ios/web/public/js_messaging/web_frame_util.h"
  24. #import "ios/web/public/web_state.h"
  25. #include "services/metrics/public/cpp/ukm_builders.h"
  26. #if !defined(__has_feature) || !__has_feature(objc_arc)
  27. #error "This file requires ARC support."
  28. #endif
  29. using autofill::FieldPropertiesFlags;
  30. using autofill::FormData;
  31. using autofill::FormRendererId;
  32. using autofill::FieldRendererId;
  33. using autofill::PasswordFormFillData;
  34. using base::SysNSStringToUTF16;
  35. using base::UTF16ToUTF8;
  36. using password_manager::FillData;
  37. using password_manager::GetPageURLAndCheckTrustLevel;
  38. using password_manager::JsonStringToFormData;
  39. namespace password_manager {
  40. bool GetPageURLAndCheckTrustLevel(web::WebState* web_state,
  41. GURL* __nullable page_url) {
  42. auto trustLevel = web::URLVerificationTrustLevel::kNone;
  43. GURL dummy;
  44. if (!page_url) {
  45. page_url = &dummy;
  46. }
  47. *page_url = web_state->GetCurrentURL(&trustLevel);
  48. return trustLevel == web::URLVerificationTrustLevel::kAbsolute;
  49. }
  50. } // namespace password_manager
  51. namespace {
  52. // Script command prefix for form changes. Possible command to be sent from
  53. // injected JS is 'passwordForm.submitButtonClick'.
  54. constexpr char kCommandPrefix[] = "passwordForm";
  55. } // namespace
  56. @interface PasswordFormHelper ()
  57. // Handler for injected JavaScript callbacks.
  58. - (BOOL)handleScriptCommand:(const base::Value&)JSONCommand;
  59. // Parses the |jsonString| which contatins the password forms found on a web
  60. // page to populate the |forms| vector.
  61. - (void)getPasswordForms:(std::vector<FormData>*)forms
  62. fromJSON:(NSString*)jsonString
  63. pageURL:(const GURL&)pageURL;
  64. // Records both UMA & UKM metrics.
  65. - (void)recordFormFillingSuccessMetrics:(bool)success;
  66. @end
  67. @implementation PasswordFormHelper {
  68. // The WebState this instance is observing. Will be null after
  69. // -webStateDestroyed: has been called.
  70. web::WebState* _webState;
  71. // Bridge to observe WebState from Objective-C.
  72. std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge;
  73. // Bridge to observe form activity in |_webState|.
  74. std::unique_ptr<autofill::FormActivityObserverBridge>
  75. _formActivityObserverBridge;
  76. // Subscription for JS message.
  77. base::CallbackListSubscription _subscription;
  78. }
  79. #pragma mark - Properties
  80. @synthesize fieldDataManager = _fieldDataManager;
  81. - (const GURL&)lastCommittedURL {
  82. return _webState ? _webState->GetLastCommittedURL() : GURL::EmptyGURL();
  83. }
  84. #pragma mark - Initialization
  85. - (instancetype)initWithWebState:(web::WebState*)webState {
  86. self = [super init];
  87. if (self) {
  88. DCHECK(webState);
  89. _webState = webState;
  90. _webStateObserverBridge =
  91. std::make_unique<web::WebStateObserverBridge>(self);
  92. _webState->AddObserver(_webStateObserverBridge.get());
  93. _formActivityObserverBridge =
  94. std::make_unique<autofill::FormActivityObserverBridge>(_webState, self);
  95. UniqueIDDataTabHelper* uniqueIDDataTabHelper =
  96. UniqueIDDataTabHelper::FromWebState(_webState);
  97. _fieldDataManager = uniqueIDDataTabHelper->GetFieldDataManager();
  98. __weak PasswordFormHelper* weakSelf = self;
  99. auto callback =
  100. base::BindRepeating(^(const base::Value& JSON, const GURL& originURL,
  101. bool interacting, web::WebFrame* senderFrame) {
  102. // Passwords is only supported on main frame.
  103. if (senderFrame->IsMainFrame()) {
  104. // |originURL| and |interacting| aren't used.
  105. [weakSelf handleScriptCommand:JSON];
  106. }
  107. });
  108. _subscription =
  109. _webState->AddScriptCommandCallback(callback, kCommandPrefix);
  110. }
  111. return self;
  112. }
  113. #pragma mark - Dealloc
  114. - (void)dealloc {
  115. if (_webState) {
  116. _webState->RemoveObserver(_webStateObserverBridge.get());
  117. }
  118. }
  119. #pragma mark - CRWWebStateObserver
  120. - (void)webStateDestroyed:(web::WebState*)webState {
  121. DCHECK_EQ(_webState, webState);
  122. if (_webState) {
  123. _webState->RemoveObserver(_webStateObserverBridge.get());
  124. _webState = nullptr;
  125. }
  126. _webStateObserverBridge.reset();
  127. _formActivityObserverBridge.reset();
  128. }
  129. #pragma mark - FormActivityObserver
  130. - (void)webState:(web::WebState*)webState
  131. didSubmitDocumentWithFormNamed:(const std::string&)formName
  132. withData:(const std::string&)formData
  133. hasUserGesture:(BOOL)hasUserGesture
  134. formInMainFrame:(BOOL)formInMainFrame
  135. inFrame:(web::WebFrame*)frame {
  136. DCHECK_EQ(_webState, webState);
  137. GURL pageURL = webState->GetLastCommittedURL();
  138. if (pageURL.DeprecatedGetOriginAsURL() != frame->GetSecurityOrigin()) {
  139. // Passwords is only supported on main frame and iframes with the same
  140. // origin.
  141. return;
  142. }
  143. if (!self.delegate || formData.empty()) {
  144. return;
  145. }
  146. std::vector<FormData> forms;
  147. NSString* nsFormData = [NSString stringWithUTF8String:formData.c_str()];
  148. autofill::ExtractFormsData(nsFormData, false, std::u16string(), pageURL,
  149. pageURL.DeprecatedGetOriginAsURL(), &forms);
  150. if (forms.size() != 1) {
  151. return;
  152. }
  153. // Extract FieldDataManager data for observed fields.
  154. [self extractKnownFieldData:forms[0]];
  155. [self.delegate formHelper:self
  156. didSubmitForm:forms[0]
  157. inMainFrame:formInMainFrame];
  158. }
  159. #pragma mark - Private methods
  160. - (BOOL)handleScriptCommand:(const base::Value&)JSONCommand {
  161. const std::string* command = JSONCommand.GetDict().FindString("command");
  162. if (!command || *command != "passwordForm.submitButtonClick") {
  163. return NO;
  164. }
  165. GURL pageURL;
  166. if (!GetPageURLAndCheckTrustLevel(_webState, &pageURL)) {
  167. return NO;
  168. }
  169. FormData form;
  170. if (!autofill::ExtractFormData(JSONCommand, false, std::u16string(), pageURL,
  171. pageURL.DeprecatedGetOriginAsURL(), &form)) {
  172. return NO;
  173. }
  174. // Extract FieldDataManager data for observed fields.
  175. [self extractKnownFieldData:form];
  176. if (_webState && self.delegate) {
  177. [self.delegate formHelper:self didSubmitForm:form inMainFrame:YES];
  178. return YES;
  179. }
  180. return NO;
  181. }
  182. - (void)getPasswordForms:(std::vector<FormData>*)forms
  183. fromJSON:(NSString*)JSONString
  184. pageURL:(const GURL&)pageURL {
  185. std::vector<FormData> formsData;
  186. if (!autofill::ExtractFormsData(JSONString, false, std::u16string(), pageURL,
  187. pageURL.DeprecatedGetOriginAsURL(),
  188. &formsData)) {
  189. return;
  190. }
  191. // Extract FieldDataManager data for observed form fields.
  192. for (FormData& form : formsData) {
  193. [self extractKnownFieldData:form];
  194. }
  195. *forms = std::move(formsData);
  196. }
  197. // Extracts known field data.
  198. - (void)extractKnownFieldData:(FormData&)form {
  199. for (auto& field : form.fields) {
  200. if (self.fieldDataManager->HasFieldData(field.unique_renderer_id)) {
  201. field.user_input =
  202. self.fieldDataManager->GetUserInput(field.unique_renderer_id);
  203. field.properties_mask = self.fieldDataManager->GetFieldPropertiesMask(
  204. field.unique_renderer_id);
  205. }
  206. }
  207. }
  208. - (void)recordFormFillingSuccessMetrics:(bool)success {
  209. base::UmaHistogramBoolean("PasswordManager.FillingSuccessIOS", success);
  210. ukm::SourceId source_id = ukm::GetSourceIdForWebStateDocument(_webState);
  211. if (source_id == ukm::kInvalidSourceId || !(ukm::UkmRecorder::Get())) {
  212. return;
  213. }
  214. ukm::builders::PasswordManager_PasswordFillingIOS(source_id)
  215. .SetFillingSuccess(success)
  216. .Record(ukm::UkmRecorder::Get());
  217. }
  218. #pragma mark - Public methods
  219. - (void)findPasswordFormsWithCompletionHandler:
  220. (void (^)(const std::vector<FormData>&, uint32_t))completionHandler {
  221. if (!_webState) {
  222. return;
  223. }
  224. web::WebFrame* mainFrame = web::GetMainFrame(_webState);
  225. if (!mainFrame) {
  226. return;
  227. }
  228. GURL pageURL;
  229. if (!GetPageURLAndCheckTrustLevel(_webState, &pageURL)) {
  230. return;
  231. }
  232. __weak PasswordFormHelper* weakSelf = self;
  233. password_manager::PasswordManagerJavaScriptFeature::GetInstance()
  234. ->FindPasswordFormsInFrame(
  235. mainFrame, base::BindOnce(^(NSString* JSONString) {
  236. std::vector<FormData> forms;
  237. [weakSelf getPasswordForms:&forms
  238. fromJSON:JSONString
  239. pageURL:pageURL];
  240. // Find the maximum extracted value.
  241. uint32_t maxID = 0;
  242. for (const auto& form : forms) {
  243. if (form.unique_renderer_id) {
  244. maxID = std::max(maxID, form.unique_renderer_id.value());
  245. }
  246. for (const auto& field : form.fields) {
  247. if (field.unique_renderer_id) {
  248. maxID = std::max(maxID, field.unique_renderer_id.value());
  249. }
  250. }
  251. }
  252. completionHandler(forms, maxID);
  253. }));
  254. }
  255. // TODO(crbug.com/1350997): Filling on page load doesn't happen anymore
  256. // so this method should be deleted.
  257. - (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
  258. inFrame:(web::WebFrame*)frame
  259. completionHandler:(nullable void (^)(BOOL))completionHandler {
  260. web::WebFrame* mainFrame = web::GetMainFrame(_webState);
  261. if (!mainFrame) {
  262. return;
  263. }
  264. // Necessary copy so the values can be used inside a block.
  265. FieldRendererId usernameID = formData.username_field.unique_renderer_id;
  266. FieldRendererId passwordID = formData.password_field.unique_renderer_id;
  267. std::u16string usernameValue = formData.username_field.value;
  268. std::u16string passwordValue = formData.password_field.value;
  269. // Don't fill if:
  270. // 1. Waiting for the user to type a username.
  271. // 2. |formData|'s origin is not matching the origin of the last commited URL.
  272. // 3. If a field has user typed input or input filled on user trigger.
  273. if (formData.wait_for_username ||
  274. formData.url.DeprecatedGetOriginAsURL() !=
  275. self.lastCommittedURL.DeprecatedGetOriginAsURL() ||
  276. self.fieldDataManager->WasAutofilledOnUserTrigger(passwordID) ||
  277. self.fieldDataManager->DidUserType(passwordID)) {
  278. if (completionHandler) {
  279. completionHandler(NO);
  280. }
  281. return;
  282. }
  283. // Send JSON over to the web view.
  284. __weak PasswordFormHelper* weakSelf = self;
  285. password_manager::PasswordManagerJavaScriptFeature::GetInstance()
  286. ->FillPasswordForm(mainFrame, formData, UTF16ToUTF8(usernameValue),
  287. UTF16ToUTF8(passwordValue),
  288. base::BindOnce(^(BOOL success) {
  289. PasswordFormHelper* strongSelf = weakSelf;
  290. if (!strongSelf) {
  291. return;
  292. }
  293. [strongSelf recordFormFillingSuccessMetrics:success];
  294. if (success) {
  295. strongSelf.fieldDataManager->UpdateFieldDataMap(
  296. usernameID, usernameValue,
  297. FieldPropertiesFlags::kAutofilledOnPageLoad);
  298. strongSelf.fieldDataManager->UpdateFieldDataMap(
  299. passwordID, passwordValue,
  300. FieldPropertiesFlags::kAutofilledOnPageLoad);
  301. }
  302. if (completionHandler) {
  303. completionHandler(success);
  304. }
  305. }));
  306. }
  307. - (void)fillPasswordForm:(FormRendererId)formIdentifier
  308. inFrame:(web::WebFrame*)frame
  309. newPasswordIdentifier:(FieldRendererId)newPasswordIdentifier
  310. confirmPasswordIdentifier:(FieldRendererId)confirmPasswordIdentifier
  311. generatedPassword:(NSString*)generatedPassword
  312. completionHandler:(nullable void (^)(BOOL))completionHandler {
  313. web::WebFrame* mainFrame = web::GetMainFrame(_webState);
  314. if (!mainFrame) {
  315. return;
  316. }
  317. // Send JSON over to the web view.
  318. __weak PasswordFormHelper* weakSelf = self;
  319. password_manager::PasswordManagerJavaScriptFeature::GetInstance()
  320. ->FillPasswordForm(
  321. mainFrame, formIdentifier, newPasswordIdentifier,
  322. confirmPasswordIdentifier, generatedPassword,
  323. base::BindOnce(
  324. ^(BOOL success) {
  325. if (success) {
  326. weakSelf.fieldDataManager->UpdateFieldDataMap(
  327. newPasswordIdentifier,
  328. SysNSStringToUTF16(generatedPassword),
  329. FieldPropertiesFlags::kAutofilledOnUserTrigger);
  330. weakSelf.fieldDataManager->UpdateFieldDataMap(
  331. confirmPasswordIdentifier,
  332. SysNSStringToUTF16(generatedPassword),
  333. FieldPropertiesFlags::kAutofilledOnUserTrigger);
  334. }
  335. if (completionHandler) {
  336. completionHandler(success);
  337. }
  338. }));
  339. }
  340. - (void)fillPasswordFormWithFillData:(const password_manager::FillData&)fillData
  341. inFrame:(web::WebFrame*)frame
  342. triggeredOnField:(FieldRendererId)uniqueFieldID
  343. completionHandler:
  344. (nullable void (^)(BOOL))completionHandler {
  345. web::WebFrame* mainFrame = web::GetMainFrame(_webState);
  346. if (!mainFrame) {
  347. return;
  348. }
  349. // Necessary copy so the values can be used inside a block.
  350. FieldRendererId usernameID = fillData.username_element_id;
  351. FieldRendererId passwordID = fillData.password_element_id;
  352. std::u16string usernameValue = fillData.username_value;
  353. std::u16string passwordValue = fillData.password_value;
  354. // Do not fill the username if filling was triggered on a password field and
  355. // the username field has user typed input.
  356. BOOL fillUsername = uniqueFieldID == usernameID ||
  357. !_fieldDataManager->DidUserType(usernameID);
  358. __weak PasswordFormHelper* weakSelf = self;
  359. password_manager::PasswordManagerJavaScriptFeature::GetInstance()
  360. ->FillPasswordForm(
  361. mainFrame, fillData, fillUsername, UTF16ToUTF8(usernameValue),
  362. UTF16ToUTF8(passwordValue), base::BindOnce(^(BOOL success) {
  363. PasswordFormHelper* strongSelf = weakSelf;
  364. if (!strongSelf) {
  365. return;
  366. }
  367. [strongSelf recordFormFillingSuccessMetrics:success];
  368. if (success) {
  369. strongSelf.fieldDataManager->UpdateFieldDataMap(
  370. usernameID, usernameValue,
  371. FieldPropertiesFlags::kAutofilledOnUserTrigger);
  372. strongSelf.fieldDataManager->UpdateFieldDataMap(
  373. passwordID, passwordValue,
  374. FieldPropertiesFlags::kAutofilledOnUserTrigger);
  375. }
  376. if (completionHandler) {
  377. completionHandler(success);
  378. }
  379. }));
  380. }
  381. // Finds the password form named |formName| and calls
  382. // |completionHandler| with the populated |FormData| data structure. |found| is
  383. // YES if the current form was found successfully, NO otherwise.
  384. - (void)extractPasswordFormData:(FormRendererId)formIdentifier
  385. completionHandler:(void (^)(BOOL found, const FormData& form))
  386. completionHandler {
  387. DCHECK(completionHandler);
  388. if (!_webState) {
  389. return;
  390. }
  391. web::WebFrame* mainFrame = web::GetMainFrame(_webState);
  392. if (!mainFrame) {
  393. return;
  394. }
  395. GURL pageURL;
  396. if (!GetPageURLAndCheckTrustLevel(_webState, &pageURL)) {
  397. completionHandler(NO, FormData());
  398. return;
  399. }
  400. password_manager::PasswordManagerJavaScriptFeature::GetInstance()
  401. ->ExtractForm(
  402. mainFrame, formIdentifier, base::BindOnce(^(NSString* jsonString) {
  403. FormData formData;
  404. if (!JsonStringToFormData(jsonString, &formData, pageURL)) {
  405. completionHandler(NO, FormData());
  406. return;
  407. }
  408. completionHandler(YES, formData);
  409. }));
  410. }
  411. - (void)setUpForUniqueIDsWithInitialState:(uint32_t)nextAvailableID
  412. inFrame:(web::WebFrame*)frame {
  413. autofill::FormUtilJavaScriptFeature::GetInstance()
  414. ->SetUpForUniqueIDsWithInitialState(frame, nextAvailableID);
  415. }
  416. - (void)updateFieldDataOnUserInput:(autofill::FieldRendererId)field_id
  417. inputValue:(NSString*)value {
  418. self.fieldDataManager->UpdateFieldDataMap(
  419. field_id, base::SysNSStringToUTF16(value),
  420. autofill::FieldPropertiesFlags::kUserTyped);
  421. }
  422. @end