Commit 6b8c8108 authored by Matthias Körber's avatar Matthias Körber Committed by Commit Bot

[Autofill] Crowdsourcing for CVC fields.

With this feature, votes for the |CREDIT_CARD_VERIFICATION_CODE|-type
are generated for fields which either have the CVC value, which was used
to unlock the server-cards, or are heuristically detected to be most
likely the CVC field of a credit-card form.

Bug: 
Change-Id: If3b54afb801dec4aec5856a5f97a68cee56870fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1762215
Commit-Queue: Matthias Körber <koerber@google.com>
Reviewed-by: default avatarMaxim Kolosovskiy <kolos@chromium.org>
Reviewed-by: default avatarChristos Froussios <cfroussios@chromium.org>
Cr-Commit-Position: refs/heads/master@{#692111}
parent fda83664
...@@ -57,8 +57,6 @@ ...@@ -57,8 +57,6 @@
#include "components/autofill/core/browser/geo/country_names.h" #include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/geo/phone_number_i18n.h" #include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/logging/log_manager.h" #include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/metrics/address_form_event_logger.h"
#include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h"
#include "components/autofill/core/browser/metrics/form_events.h" #include "components/autofill/core/browser/metrics/form_events.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h" #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/payments/payments_client.h"
...@@ -255,6 +253,93 @@ void LogAutofillTypePredictionsAvailable( ...@@ -255,6 +253,93 @@ void LogAutofillTypePredictionsAvailable(
<< std::move(buffer); << std::move(buffer);
} }
// Finds the first field in |form_structure| with |field.value|=|value|.
AutofillField* FindFirstFieldWithValue(const FormStructure& form_structure,
const base::string16& value) {
for (const auto& field : form_structure) {
base::string16 trimmed_value;
base::TrimWhitespace(field->value, base::TRIM_ALL, &trimmed_value);
if (trimmed_value == value)
return field.get();
}
return nullptr;
}
// Heuristically identifies all possible credit card verification fields.
AutofillField* HeuristicallyFindCVCField(const FormStructure& form_structure) {
// Stores a pointer to the explicitly found expiration year.
bool found_explicit_expiration_year_field = false;
// The first pass checks the existence of an explicitly marked field for the
// credit card expiration year.
for (const auto& field : form_structure) {
const ServerFieldTypeSet& type_set = field->possible_types();
if (type_set.find(CREDIT_CARD_EXP_2_DIGIT_YEAR) != type_set.end() ||
type_set.find(CREDIT_CARD_EXP_4_DIGIT_YEAR) != type_set.end()) {
found_explicit_expiration_year_field = true;
break;
}
}
// Keeps track if a credit card number field was found.
bool credit_card_number_found = false;
// In the second pass, the CVC field is heuristically searched for.
// A field is considered a CVC field, iff:
// * it appears after the credit card number field;
// * it has the |UNKNOWN_TYPE| prediction;
// * it does not look like an expiration year or an expiration year was
// already found;
// * it is filled with a 3-4 digit number;
for (const auto& field : form_structure) {
const ServerFieldTypeSet& type_set = field->possible_types();
// Checks if the field is of |CREDIT_CARD_NUMBER| type.
if (type_set.find(CREDIT_CARD_NUMBER) != type_set.end()) {
credit_card_number_found = true;
continue;
}
// Skip the field if no credit card number was found yet.
if (!credit_card_number_found) {
continue;
}
// Don't consider fields that already have any prediction.
if (type_set.find(UNKNOWN_TYPE) == type_set.end())
continue;
// |UNKNOWN_TYPE| should come alone.
DCHECK_EQ(1u, type_set.size());
base::string16 trimmed_value;
base::TrimWhitespace(field->value, base::TRIM_ALL, &trimmed_value);
// Skip the field if it can be confused with a expiration year.
if (!found_explicit_expiration_year_field &&
IsPlausible4DigitExpirationYear(trimmed_value)) {
continue;
}
// Skip the field if its value does not like a CVC value.
if (!IsPlausibleCreditCardCVCNumber(trimmed_value))
continue;
return field.get();
}
return nullptr;
}
// Iff the CVC of the credit card is known, find the first field with this
// value. Otherwise, heuristically search for the CVC field if any.
AutofillField* FindBestPossibleCVCField(
const FormStructure& form_structure,
base::string16 last_unlocked_credit_card_cvc) {
if (!last_unlocked_credit_card_cvc.empty())
return FindFirstFieldWithValue(form_structure,
last_unlocked_credit_card_cvc);
return HeuristicallyFindCVCField(form_structure);
}
} // namespace } // namespace
AutofillManager::FillingContext::FillingContext() = default; AutofillManager::FillingContext::FillingContext() = default;
...@@ -565,8 +650,8 @@ bool AutofillManager::MaybeStartVoteUploadProcess( ...@@ -565,8 +650,8 @@ bool AutofillManager::MaybeStartVoteUploadProcess(
// number of outstanding tasks. https://crbug.com/974249 // number of outstanding tasks. https://crbug.com/974249
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE}, {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&AutofillManager::DeterminePossibleFieldTypesForUpload, base::BindOnce(&AutofillManager::DeterminePossibleFieldTypesForUpload,
copied_profiles, copied_credit_cards, app_locale_, copied_profiles, copied_credit_cards,
raw_form), last_unlocked_credit_card_cvc_, app_locale_, raw_form),
base::BindOnce(&AutofillManager::UploadFormDataAsyncCallback, base::BindOnce(&AutofillManager::UploadFormDataAsyncCallback,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(),
base::Owned(form_structure.release()), base::Owned(form_structure.release()),
...@@ -1209,6 +1294,8 @@ void AutofillManager::OnCreditCardFetched(bool did_succeed, ...@@ -1209,6 +1294,8 @@ void AutofillManager::OnCreditCardFetched(bool did_succeed,
return; return;
} }
last_unlocked_credit_card_cvc_ = cvc;
FormStructure* form_structure = nullptr; FormStructure* form_structure = nullptr;
AutofillField* autofill_field = nullptr; AutofillField* autofill_field = nullptr;
if (!GetCachedFormAndField(credit_card_form_, credit_card_field_, if (!GetCachedFormAndField(credit_card_form_, credit_card_field_,
...@@ -1304,6 +1391,11 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form, ...@@ -1304,6 +1391,11 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form,
ServerFieldTypeSet non_empty_types; ServerFieldTypeSet non_empty_types;
personal_data_->GetNonEmptyTypes(&non_empty_types); personal_data_->GetNonEmptyTypes(&non_empty_types);
// AS CVC is not stored, treat it separately.
if (!last_unlocked_credit_card_cvc_.empty() ||
non_empty_types.find(CREDIT_CARD_NUMBER) != non_empty_types.end()) {
non_empty_types.insert(CREDIT_CARD_VERIFICATION_CODE);
}
download_manager_->StartUploadRequest( download_manager_->StartUploadRequest(
submitted_form, was_autofilled, non_empty_types, submitted_form, was_autofilled, non_empty_types,
...@@ -1341,6 +1433,7 @@ void AutofillManager::Reset() { ...@@ -1341,6 +1433,7 @@ void AutofillManager::Reset() {
credit_card_query_id_ = -1; credit_card_query_id_ = -1;
credit_card_form_ = FormData(); credit_card_form_ = FormData();
credit_card_field_ = FormFieldData(); credit_card_field_ = FormFieldData();
last_unlocked_credit_card_cvc_.clear();
credit_card_action_ = AutofillDriver::FORM_DATA_ACTION_PREVIEW; credit_card_action_ = AutofillDriver::FORM_DATA_ACTION_PREVIEW;
initial_interaction_timestamp_ = TimeTicks(); initial_interaction_timestamp_ = TimeTicks();
external_delegate_->Reset(); external_delegate_->Reset();
...@@ -1472,9 +1565,9 @@ void AutofillManager::FillOrPreviewDataModelForm( ...@@ -1472,9 +1565,9 @@ void AutofillManager::FillOrPreviewDataModelForm(
filling_contexts_map_.find(form_structure->GetIdentifierForRefill()); filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
if (itr != filling_contexts_map_.end()) if (itr != filling_contexts_map_.end())
filling_context = itr->second.get(); filling_context = itr->second.get();
bool could_attempt_refill = bool could_attempt_refill = filling_context != nullptr &&
filling_context != nullptr && !filling_context->attempted_refill && !filling_context->attempted_refill &&
!is_refill && !is_credit_card; !is_refill && !is_credit_card;
for (size_t i = 0; i < form_structure->field_count(); ++i) { for (size_t i = 0; i < form_structure->field_count(); ++i) {
// On the renderer, the section is used regardless of the autofill status. // On the renderer, the section is used regardless of the autofill status.
...@@ -1863,13 +1956,13 @@ void AutofillManager::UpdateInitialInteractionTimestamp( ...@@ -1863,13 +1956,13 @@ void AutofillManager::UpdateInitialInteractionTimestamp(
void AutofillManager::DeterminePossibleFieldTypesForUpload( void AutofillManager::DeterminePossibleFieldTypesForUpload(
const std::vector<AutofillProfile>& profiles, const std::vector<AutofillProfile>& profiles,
const std::vector<CreditCard>& credit_cards, const std::vector<CreditCard>& credit_cards,
const base::string16& last_unlocked_credit_card_cvc,
const std::string& app_locale, const std::string& app_locale,
FormStructure* submitted_form) { FormStructure* submitted_form) {
// For each field in the |submitted_form|, extract the value. Then for each // For each field in the |submitted_form|, extract the value. Then for each
// profile or credit card, identify any stored types that match the value. // profile or credit card, identify any stored types that match the value.
for (size_t i = 0; i < submitted_form->field_count(); ++i) { for (size_t i = 0; i < submitted_form->field_count(); ++i) {
AutofillField* field = submitted_form->field(i); AutofillField* field = submitted_form->field(i);
if (!field->possible_types().empty() && field->IsEmpty()) { if (!field->possible_types().empty() && field->IsEmpty()) {
// This is a password field in a sign-in form. Skip checking its type // This is a password field in a sign-in form. Skip checking its type
// since |field->value| is not set. // since |field->value| is not set.
...@@ -1907,6 +2000,16 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload( ...@@ -1907,6 +2000,16 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
field->set_possible_types(matching_types); field->set_possible_types(matching_types);
} }
// As CVCs are not stored, run special heuristics to detect CVC-like values.
AutofillField* cvc_field =
FindBestPossibleCVCField(*submitted_form, last_unlocked_credit_card_cvc);
if (cvc_field) {
ServerFieldTypeSet possible_types = cvc_field->possible_types();
possible_types.erase(UNKNOWN_TYPE);
possible_types.insert(CREDIT_CARD_VERIFICATION_CODE);
cvc_field->set_possible_types(possible_types);
}
AutofillManager::DisambiguateUploadTypes(submitted_form); AutofillManager::DisambiguateUploadTypes(submitted_form);
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -473,6 +474,7 @@ class AutofillManager : public AutofillHandler, ...@@ -473,6 +474,7 @@ class AutofillManager : public AutofillHandler,
static void DeterminePossibleFieldTypesForUpload( static void DeterminePossibleFieldTypesForUpload(
const std::vector<AutofillProfile>& profiles, const std::vector<AutofillProfile>& profiles,
const std::vector<CreditCard>& credit_cards, const std::vector<CreditCard>& credit_cards,
const base::string16& last_unlocked_credit_card_cvc,
const std::string& app_locale, const std::string& app_locale,
FormStructure* submitted_form); FormStructure* submitted_form);
...@@ -591,6 +593,7 @@ class AutofillManager : public AutofillHandler, ...@@ -591,6 +593,7 @@ class AutofillManager : public AutofillHandler,
FormData credit_card_form_; FormData credit_card_form_;
FormFieldData credit_card_field_; FormFieldData credit_card_field_;
CreditCard credit_card_; CreditCard credit_card_;
base::string16 last_unlocked_credit_card_cvc_;
// Ablation experiment turns off autofill, but logging still has to be kept // Ablation experiment turns off autofill, but logging still has to be kept
// for metrics analysis. // for metrics analysis.
...@@ -641,6 +644,19 @@ class AutofillManager : public AutofillHandler, ...@@ -641,6 +644,19 @@ class AutofillManager : public AutofillHandler,
DeterminePossibleFieldTypesForUploadStressTest); DeterminePossibleFieldTypesForUploadStressTest);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DisambiguateUploadTypes); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DisambiguateUploadTypes);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, CrowdsourceUPIVPA); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, CrowdsourceUPIVPA);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, CrowdsourceCVCFieldByValue);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceCVCFieldAfterExpDateByHeuristics);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceCVCFieldDisableHeurisitcs);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceNoCVCDueToInvalidCandidateValue);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceNoCVCFieldDueToMissingCreditCardNumber);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceCVCFieldAfterInvalidExpDateByHeuristics);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
CrowdsourceCVCFieldBeforeExpDateByHeuristics);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
DisabledAutofillDispatchesError); DisabledAutofillDispatchesError);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
...@@ -73,8 +74,8 @@ const char kShippingMode[] = "shipping"; ...@@ -73,8 +74,8 @@ const char kShippingMode[] = "shipping";
const int kCommonNamePrefixRemovalFieldThreshold = 3; const int kCommonNamePrefixRemovalFieldThreshold = 3;
const int kMinCommonNamePrefixLength = 16; const int kMinCommonNamePrefixLength = 16;
// Returns true if the scheme given by |url| is one for which autfill is allowed // Returns true if the scheme given by |url| is one for which autofill is
// to activate. By default this only returns true for HTTP and HTTPS. // allowed to activate. By default this only returns true for HTTP and HTTPS.
bool HasAllowedScheme(const GURL& url) { bool HasAllowedScheme(const GURL& url) {
return url.SchemeIsHTTPOrHTTPS() || return url.SchemeIsHTTPOrHTTPS() ||
base::FeatureList::IsEnabled( base::FeatureList::IsEnabled(
......
...@@ -91,7 +91,7 @@ bool HasCorrectLength(const base::string16& number) { ...@@ -91,7 +91,7 @@ bool HasCorrectLength(const base::string16& number) {
return true; return true;
} }
// TODO (crbug.com/927767): Add unit tests for this function. // TODO(crbug.com/927767): Add unit tests for this function.
bool PassesLuhnCheck(const base::string16& number) { bool PassesLuhnCheck(const base::string16& number) {
// Use the Luhn formula [3] to validate the number. // Use the Luhn formula [3] to validate the number.
// [3] http://en.wikipedia.org/wiki/Luhn_algorithm // [3] http://en.wikipedia.org/wiki/Luhn_algorithm
...@@ -351,4 +351,12 @@ bool IsInternationalBankAccountNumber(const base::string16& value) { ...@@ -351,4 +351,12 @@ bool IsInternationalBankAccountNumber(const base::string16& value) {
base::ASCIIToUTF16(kInternationalBankAccountNumberRe)); base::ASCIIToUTF16(kInternationalBankAccountNumberRe));
} }
bool IsPlausibleCreditCardCVCNumber(const base::string16& value) {
return MatchesPattern(value, base::ASCIIToUTF16(kCreditCardCVCPattern));
}
bool IsPlausible4DigitExpirationYear(const base::string16& value) {
return MatchesPattern(value,
base::ASCIIToUTF16(kCreditCard4DigitExpYearPattern));
}
} // namespace autofill } // namespace autofill
...@@ -93,6 +93,12 @@ bool IsUPIVirtualPaymentAddress(const base::string16& value); ...@@ -93,6 +93,12 @@ bool IsUPIVirtualPaymentAddress(const base::string16& value);
// (IBAN). See https://en.wikipedia.org/wiki/International_Bank_Account_Number // (IBAN). See https://en.wikipedia.org/wiki/International_Bank_Account_Number
bool IsInternationalBankAccountNumber(const base::string16& value); bool IsInternationalBankAccountNumber(const base::string16& value);
// Return true if |value| is a 3 or 4 digit number.
bool IsPlausibleCreditCardCVCNumber(const base::string16& value);
// Returns true if the value is a 4 digit year in this century.
bool IsPlausible4DigitExpirationYear(const base::string16& value);
} // namespace autofill } // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_VALIDATION_H_ #endif // COMPONENTS_AUTOFILL_CORE_BROWSER_VALIDATION_H_
...@@ -38,26 +38,17 @@ struct SecurityCodeCardTypePair { ...@@ -38,26 +38,17 @@ struct SecurityCodeCardTypePair {
// From https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm // From https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm
const char* const kValidNumbers[] = { const char* const kValidNumbers[] = {
"378282246310005", "378282246310005", "3714 4963 5398 431", "3787-3449-3671-000",
"3714 4963 5398 431", "5610591081018250", "3056 9309 0259 04", "3852-0000-0232-37",
"3787-3449-3671-000", "6011111111111117", "6011 0009 9013 9424", "3530-1113-3330-0000",
"5610591081018250",
"3056 9309 0259 04",
"3852-0000-0232-37",
"6011111111111117",
"6011 0009 9013 9424",
"3530-1113-3330-0000",
"3566002020360505", "3566002020360505",
"5555 5555 5555 4444", // Mastercard. "5555 5555 5555 4444", // Mastercard.
"5105-1051-0510-5100", "5105-1051-0510-5100",
"4111111111111111", // Visa. "4111111111111111", // Visa.
"4012 8888 8888 1881", "4012 8888 8888 1881", "4222-2222-2222-2", "5019717010103742",
"4222-2222-2222-2", "6331101999990016", "6247130048162403",
"5019717010103742", "4532261615476013542", // Visa, 19 digits.
"6331101999990016", "6362970000457013", // Elo
"6247130048162403",
"4532261615476013542", // Visa, 19 digits.
"6362970000457013", // Elo
}; };
const char* const kInvalidNumbers[] = { const char* const kInvalidNumbers[] = {
"4111 1111 112", /* too short */ "4111 1111 112", /* too short */
...@@ -78,15 +69,15 @@ const IntExpirationDate kInvalidCreditCardIntExpirationDate[] = { ...@@ -78,15 +69,15 @@ const IntExpirationDate kInvalidCreditCardIntExpirationDate[] = {
{ 2015, 0 }, // Zero is legal in the CC class but is not a valid date. { 2015, 0 }, // Zero is legal in the CC class but is not a valid date.
}; };
const SecurityCodeCardTypePair kValidSecurityCodeCardTypePairs[] = { const SecurityCodeCardTypePair kValidSecurityCodeCardTypePairs[] = {
{ "323", kGenericCard }, // 3-digit CSC. {"323", kGenericCard}, // 3-digit CSC.
{ "3234", kAmericanExpressCard }, // 4-digit CSC. {"3234", kAmericanExpressCard}, // 4-digit CSC.
}; };
const SecurityCodeCardTypePair kInvalidSecurityCodeCardTypePairs[] = { const SecurityCodeCardTypePair kInvalidSecurityCodeCardTypePairs[] = {
{ "32", kGenericCard }, // CSC too short. {"32", kGenericCard}, // CSC too short.
{ "323", kAmericanExpressCard }, // CSC too short. {"323", kAmericanExpressCard}, // CSC too short.
{ "3234", kGenericCard }, // CSC too long. {"3234", kGenericCard}, // CSC too long.
{ "12345", kAmericanExpressCard }, // CSC too long. {"12345", kAmericanExpressCard}, // CSC too long.
{ "asd", kGenericCard }, // non-numeric CSC. {"asd", kGenericCard}, // non-numeric CSC.
}; };
const char* const kValidEmailAddress[] = { const char* const kValidEmailAddress[] = {
"user@example", "user@example",
...@@ -100,6 +91,14 @@ const char* const kInvalidEmailAddress[] = { ...@@ -100,6 +91,14 @@ const char* const kInvalidEmailAddress[] = {
"user@", "user@",
"user@=example.com" "user@=example.com"
}; };
const char* const kUnplausibleCreditCardExpirationYears[] = {
"2009", "2134", "1111", "abcd", "2101"};
const char* const kPlausibleCreditCardExpirationYears[] = {"2018", "2099",
"2010", "2050"};
const char* const kUnplausibleCreditCardCVCNumbers[] = {"abc", "21", "11111",
"21a1"};
const char* const kPlausibleCreditCardCVCNumbers[] = {"1234", "2099", "111",
"982"};
} // namespace } // namespace
TEST(AutofillValidation, IsValidCreditCardNumber) { TEST(AutofillValidation, IsValidCreditCardNumber) {
...@@ -113,6 +112,36 @@ TEST(AutofillValidation, IsValidCreditCardNumber) { ...@@ -113,6 +112,36 @@ TEST(AutofillValidation, IsValidCreditCardNumber) {
} }
} }
// Tests the plausibility of supplied credit card expiration years.
TEST(AutofillValidation, IsPlausibleCreditCardExparationYear) {
for (const char* plausible_year : kPlausibleCreditCardExpirationYears) {
EXPECT_TRUE(
IsPlausible4DigitExpirationYear(base::ASCIIToUTF16(plausible_year)))
<< plausible_year;
}
for (const char* unplausible_year : kUnplausibleCreditCardExpirationYears) {
EXPECT_FALSE(
IsPlausible4DigitExpirationYear(base::ASCIIToUTF16(unplausible_year)))
<< unplausible_year;
}
}
// Test the plausibility of supplied CVC numbers.
TEST(AutofillValidation, IsPlausibleCreditCardCVCNumber) {
for (const char* plausible_cvc : kPlausibleCreditCardCVCNumbers) {
EXPECT_TRUE(
IsPlausibleCreditCardCVCNumber(base::ASCIIToUTF16(plausible_cvc)))
<< plausible_cvc;
}
for (const char* unplausible_cvc : kUnplausibleCreditCardCVCNumbers) {
EXPECT_FALSE(
IsPlausibleCreditCardCVCNumber(base::ASCIIToUTF16(unplausible_cvc)))
<< unplausible_cvc;
}
}
TEST(AutofillValidation, IsValidCreditCardIntExpirationDate) { TEST(AutofillValidation, IsValidCreditCardIntExpirationDate) {
base::Time now; base::Time now;
ASSERT_TRUE(base::Time::FromString(kCurrentDate, &now)); ASSERT_TRUE(base::Time::FromString(kCurrentDate, &now));
...@@ -347,8 +376,8 @@ TEST_P(AutofillCCNumberValidationTest, IsValidCreditCardNumber) { ...@@ -347,8 +376,8 @@ TEST_P(AutofillCCNumberValidationTest, IsValidCreditCardNumber) {
} }
} }
const static std::set<std::string> kAllBasicCardNetworks{ static const std::set<std::string> kAllBasicCardNetworks{
"amex", "discover", "diners", "elo", "jcb", "amex", "discover", "diners", "elo", "jcb",
"mastercard", "mir", "unionpay", "visa"}; "mastercard", "mir", "unionpay", "visa"};
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
......
...@@ -501,6 +501,12 @@ const char kUPIVirtualPaymentAddressRe[] = ...@@ -501,6 +501,12 @@ const char kUPIVirtualPaymentAddressRe[] =
const char kInternationalBankAccountNumberRe[] = const char kInternationalBankAccountNumberRe[] =
"^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$"; "^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$";
// Matches all 3 and 4 digit numbers.
const char kCreditCardCVCPattern[] = "^\\d{3,4}$";
// Matches numbers in the range [2010-2099].
const char kCreditCard4DigitExpYearPattern[] = "^[2][0][1-9][0-9]$";
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// form_structure.cc // form_structure.cc
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_ #ifndef COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_ #define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
namespace autofill { namespace autofill {
...@@ -61,6 +61,8 @@ extern const char kTravelOriginRe[]; ...@@ -61,6 +61,8 @@ extern const char kTravelOriginRe[];
extern const char kTravelDestinationRe[]; extern const char kTravelDestinationRe[];
extern const char kFlightRe[]; extern const char kFlightRe[];
extern const char kPriceRe[]; extern const char kPriceRe[];
extern const char kCreditCardCVCPattern[];
extern const char kCreditCard4DigitExpYearPattern[];
// Used to match field data that might be a UPI Virtual Payment Address. // Used to match field data that might be a UPI Virtual Payment Address.
// See: // See:
...@@ -85,4 +87,4 @@ extern const char kUrlSearchActionRe[]; ...@@ -85,4 +87,4 @@ extern const char kUrlSearchActionRe[];
} // namespace autofill } // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_REGEX_CONSTANTS_H_ #endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_REGEX_CONSTANTS_H_
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