1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include <optional>
#include "base/lazy_instance.h"
#include "base/no_destructor.h"
#include "base/strings/string_split.h"
#include "components/autofill/content/renderer/html_based_username_detector.h"
#include "components/autofill/content/renderer/synchronous_form_cache.h"
#include "components/autofill/content/renderer/timing.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/unique_ids.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "net/base/url_util.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_form_control_element.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/re2/src/re2/re2.h"
#include "url/gurl.h"
using blink::WebElement;
using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebInputElement;
using blink::WebLocalFrame;
using blink::WebString;
namespace autofill {
using form_util::ExtractOption;
namespace {
const char kPasswordSiteUrlRegex[] =
"passwords(?:-[a-z-]+\\.corp)?\\.google\\.com";
struct PasswordSiteUrlLazyInstanceTraits
: public base::internal::DestructorAtExitLazyInstanceTraits<re2::RE2> {
static re2::RE2* New(void* instance) {
return CreateMatcher(instance, kPasswordSiteUrlRegex);
}
};
base::LazyInstance<re2::RE2, PasswordSiteUrlLazyInstanceTraits>
g_password_site_matcher = LAZY_INSTANCE_INITIALIZER;
// Extracts the username predictions. |control_elements| should be all the DOM
// elements of the form, |form_data| should be the already extracted FormData
// representation of that form. |username_detector_cache| is optional, and can
// be used to spare recomputation if called multiple times for the same form.
std::vector<FieldRendererId> GetUsernamePredictions(
const FormData& form_data,
UsernameDetectorCache* username_detector_cache) {
// Dummy cache stores the predictions in case no real cache was passed to
// here.
UsernameDetectorCache dummy_cache;
if (!username_detector_cache)
username_detector_cache = &dummy_cache;
return GetPredictionsFieldBasedOnHtmlAttributes(form_data,
username_detector_cache);
}
} // namespace
re2::RE2* CreateMatcher(void* instance, const char* pattern) {
re2::RE2::Options options;
options.set_case_sensitive(false);
// Use placement new to initialize the instance in the preallocated space.
// The "(instance)" is very important to force POD type initialization.
re2::RE2* matcher = new (instance) re2::RE2(pattern, options);
DCHECK(matcher->ok());
return matcher;
}
bool IsGaiaReauthenticationForm(const blink::WebFormElement& form) {
if (!gaia::HasGaiaSchemeHostPort(form.GetDocument().Url()))
return false;
bool has_rart_field = false;
bool has_continue_field = false;
for (const WebFormControlElement& element : form.GetFormControlElements()) {
// We're only interested in the presence
// of <input type="hidden" /> elements.
const WebInputElement input = element.DynamicTo<WebInputElement>();
if (!input || input.FormControlTypeForAutofill() !=
blink::mojom::FormControlType::kInputHidden) {
continue;
}
// There must be a hidden input named "rart".
if (input.FormControlName() == "rart")
has_rart_field = true;
// There must be a hidden input named "continue", whose value points
// to a password (or password testing) site.
if (input.FormControlName() == "continue" &&
re2::RE2::PartialMatch(input.Value().Utf8(),
g_password_site_matcher.Get())) {
has_continue_field = true;
}
}
return has_rart_field && has_continue_field;
}
bool IsGaiaWithSkipSavePasswordForm(const blink::WebFormElement& form) {
if (!gaia::HasGaiaSchemeHostPort(form.GetDocument().Url()))
return false;
GURL url(form.GetDocument().Url());
std::string should_skip_password;
if (!net::GetValueForKeyInQuery(url, "ssp", &should_skip_password))
return false;
return should_skip_password == "1";
}
void ProcessFormDataAfterCreation(
FormData& form_data,
blink::WebFormElement web_form,
UsernameDetectorCache* username_detector_cache) {
if (web_form) {
form_data.set_is_gaia_with_skip_save_password_form(
IsGaiaWithSkipSavePasswordForm(web_form) ||
IsGaiaReauthenticationForm(web_form));
}
form_data.set_username_predictions(
GetUsernamePredictions(form_data, username_detector_cache));
}
std::optional<FormData> CreateFormDataFromWebForm(
const WebFormElement& web_form,
const FieldDataManager& field_data_manager,
UsernameDetectorCache* username_detector_cache,
form_util::ButtonTitlesCache* button_titles_cache,
const CallTimerState& timer_state,
const SynchronousFormCache& form_cache) {
if (!web_form) {
return std::nullopt;
}
std::optional<FormData> form_data = form_cache.GetOrExtractForm(
web_form.GetDocument(), web_form, field_data_manager, timer_state,
button_titles_cache);
if (!form_data) {
return std::nullopt;
}
ProcessFormDataAfterCreation(*form_data, web_form, username_detector_cache);
return form_data;
}
std::optional<FormData> CreateFormDataFromUnownedInputElements(
const WebLocalFrame& frame,
const FieldDataManager& field_data_manager,
UsernameDetectorCache* username_detector_cache,
const CallTimerState& timer_state,
form_util::ButtonTitlesCache* button_titles_cache,
const SynchronousFormCache& form_cache) {
std::optional<FormData> form_data = form_cache.GetOrExtractForm(
frame.GetDocument(), WebFormElement(), field_data_manager, timer_state,
button_titles_cache);
if (!form_data) {
return std::nullopt;
}
ProcessFormDataAfterCreation(*form_data, WebFormElement(),
username_detector_cache);
return form_data;
}
std::string GetSignOnRealm(const GURL& origin) {
GURL::Replacements rep;
rep.SetPathStr("");
return origin.ReplaceComponents(rep).spec();
}
} // namespace autofill
|