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 5#import "components/password_manager/ios/js_password_manager.h" 6 7#include "base/json/json_writer.h" 8#include "base/json/string_escape.h" 9#include "base/logging.h" 10#include "base/mac/foundation_util.h" 11#include "base/strings/sys_string_conversions.h" 12#include "base/values.h" 13#include "components/autofill/core/common/password_form_fill_data.h" 14#include "components/password_manager/ios/account_select_fill_data.h" 15 16#if !defined(__has_feature) || !__has_feature(objc_arc) 17#error "This file requires ARC support." 18#endif 19 20namespace password_manager { 21 22NSString* SerializeFillData(const GURL& origin, 23 const base::string16& name, 24 const base::string16& username_element, 25 const base::string16& username_value, 26 const base::string16& password_element, 27 const base::string16& password_value) { 28 base::DictionaryValue rootDict; 29 rootDict.SetString("origin", origin.spec()); 30 rootDict.SetString("name", name); 31 32 auto fieldList = std::make_unique<base::ListValue>(); 33 34 auto usernameField = std::make_unique<base::DictionaryValue>(); 35 usernameField->SetString("name", username_element); 36 usernameField->SetString("value", username_value); 37 fieldList->Append(std::move(usernameField)); 38 39 auto passwordField = std::make_unique<base::DictionaryValue>(); 40 passwordField->SetString("name", password_element); 41 passwordField->SetString("value", password_value); 42 fieldList->Append(std::move(passwordField)); 43 44 rootDict.Set("fields", std::move(fieldList)); 45 46 std::string jsonString; 47 base::JSONWriter::Write(rootDict, &jsonString); 48 return base::SysUTF8ToNSString(jsonString); 49} 50 51NSString* SerializePasswordFormFillData( 52 const autofill::PasswordFormFillData& formData) { 53 return SerializeFillData( 54 formData.origin, formData.name, formData.username_field.name, 55 formData.username_field.value, formData.password_field.name, 56 formData.password_field.value); 57} 58 59NSString* SerializeFillData(const password_manager::FillData& fillData) { 60 return SerializeFillData(fillData.origin, fillData.name, 61 fillData.username_element, fillData.username_value, 62 fillData.password_element, fillData.password_value); 63} 64 65} // namespace password_manager 66 67namespace { 68// Sanitizes |JSONString| and wraps it in quotes so it can be injected safely in 69// JavaScript. 70NSString* JSONEscape(NSString* JSONString) { 71 return base::SysUTF8ToNSString( 72 base::GetQuotedJSONString(base::SysNSStringToUTF8(JSONString))); 73} 74} // namespace 75 76@implementation JsPasswordManager { 77 // The injection receiver used to evaluate JavaScript. 78 __weak CRWJSInjectionReceiver* _receiver; 79} 80 81- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver { 82 DCHECK(receiver); 83 self = [super init]; 84 if (self) { 85 _receiver = receiver; 86 } 87 return self; 88} 89 90- (void)findPasswordFormsWithCompletionHandler: 91 (void (^)(NSString*))completionHandler { 92 DCHECK(completionHandler); 93 [_receiver executeJavaScript:@"__gCrWeb.passwords.findPasswordForms()" 94 completionHandler:^(id result, NSError*) { 95 completionHandler(base::mac::ObjCCastStrict<NSString>(result)); 96 }]; 97} 98 99- (void)extractForm:(NSString*)formName 100 completionHandler:(void (^)(NSString*))completionHandler { 101 DCHECK(completionHandler); 102 NSString* extra = [NSString 103 stringWithFormat:@"__gCrWeb.passwords.getPasswordFormDataAsString(%@)", 104 JSONEscape(formName)]; 105 [_receiver executeJavaScript:extra 106 completionHandler:^(id result, NSError*) { 107 completionHandler(base::mac::ObjCCastStrict<NSString>(result)); 108 }]; 109} 110 111- (void)fillPasswordForm:(NSString*)JSONString 112 withUsername:(NSString*)username 113 password:(NSString*)password 114 completionHandler:(void (^)(BOOL))completionHandler { 115 DCHECK(completionHandler); 116 NSString* script = [NSString 117 stringWithFormat:@"__gCrWeb.passwords.fillPasswordForm(%@, %@, %@)", 118 JSONString, JSONEscape(username), JSONEscape(password)]; 119 [_receiver executeJavaScript:script 120 completionHandler:^(id result, NSError*) { 121 completionHandler([result isEqual:@YES]); 122 }]; 123} 124 125- (void)fillPasswordForm:(NSString*)formName 126 newPasswordIdentifier:(NSString*)newPasswordIdentifier 127 confirmPasswordIdentifier:(NSString*)confirmPasswordIdentifier 128 generatedPassword:(NSString*)generatedPassword 129 completionHandler:(void (^)(BOOL))completionHandler { 130 NSString* script = [NSString 131 stringWithFormat:@"__gCrWeb.passwords." 132 @"fillPasswordFormWithGeneratedPassword(%@, %@, %@, %@)", 133 JSONEscape(formName), JSONEscape(newPasswordIdentifier), 134 JSONEscape(confirmPasswordIdentifier), 135 JSONEscape(generatedPassword)]; 136 [_receiver executeJavaScript:script 137 completionHandler:^(id result, NSError*) { 138 completionHandler([result isEqual:@YES]); 139 }]; 140} 141 142@end 143