Skip to content

Commit

Permalink
[CoF] CVC single field detection implementation
Browse files Browse the repository at this point in the history
This change adds a new logic to our field detection heuristics to uniquely identify the card-on-file case through single field CVC detection.

Bug: 1347288, 1341387
Change-Id: Ifebe68f413744690b50c3fc6bac5898e0375f608
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3786871
Reviewed-by: Dominic Battré <battre@chromium.org>
Reviewed-by: Alexander Tekle <alexandertekle@google.com>
Commit-Queue: Nakul Vaidya <nakulvaidya@google.com>
Cr-Commit-Position: refs/heads/main@{#1034252}
  • Loading branch information
Nakul Vaidya authored and Chromium LUCI CQ committed Aug 12, 2022
1 parent d90a71d commit 8597763
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 4 deletions.
4 changes: 3 additions & 1 deletion chrome/browser/autofill/form_structure_browsertest.cc
Expand Up @@ -228,7 +228,9 @@ FormStructureBrowserTest::FormStructureBrowserTest()
// TODO(crbug.com/1113970): Remove once launched.
features::kAutofillSectionUponRedundantNameInfo,
// TODO(crbug.com/1335549): Remove once launched.
features::kAutofillParseIBANFields},
features::kAutofillParseIBANFields,
// TODO(crbug.com/1341387): Remove once launched.
features::kAutofillParseVcnCardOnFileStandaloneCvcFields},
// Disabled
{});
}
Expand Down
1 change: 1 addition & 0 deletions components/autofill/core/browser/autofill_type.cc
Expand Up @@ -99,6 +99,7 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case MERCHANT_PROMO_CODE:
case IBAN_VALUE:
case UPI_VPA:
case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
return FieldTypeGroup::kNoGroup;

case MAX_VALID_FIELD_TYPE:
Expand Down
3 changes: 3 additions & 0 deletions components/autofill/core/browser/field_types.cc
Expand Up @@ -96,6 +96,7 @@ bool IsFillableFieldType(ServerFieldType field_type) {
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
case CREDIT_CARD_TYPE:
case CREDIT_CARD_VERIFICATION_CODE:
case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
return true;

case UPI_VPA:
Expand Down Expand Up @@ -316,6 +317,8 @@ base::StringPiece FieldTypeToStringPiece(ServerFieldType type) {
return "AMBIGUOUS_TYPE";
case IBAN_VALUE:
return "IBAN_VALUE";
case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
return "CREDIT_CARD_STANDALONE_VERIFICATION_CODE";
case MAX_VALID_FIELD_TYPE:
return "";
}
Expand Down
5 changes: 4 additions & 1 deletion components/autofill/core/browser/field_types.h
Expand Up @@ -243,9 +243,12 @@ enum ServerFieldType {
// banking and merchant websites used to make international transactions.
// See https://en.wikipedia.org/wiki/International_Bank_Account_Number.
IBAN_VALUE = 125,

// Standalone card verification code (CVC).
CREDIT_CARD_STANDALONE_VERIFICATION_CODE = 126,
// No new types can be added without a corresponding change to the Autofill
// server.
MAX_VALID_FIELD_TYPE = 126,
MAX_VALID_FIELD_TYPE = 127,
};

enum class FieldTypeGroup {
Expand Down
1 change: 1 addition & 0 deletions components/autofill/core/browser/field_types_unittest.cc
Expand Up @@ -43,6 +43,7 @@ TEST(FieldTypesTest, IsValidServerFieldType) {
CREDIT_CARD_EXP_4_DIGIT_YEAR,
CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
CREDIT_CARD_STANDALONE_VERIFICATION_CODE,
CREDIT_CARD_TYPE,
CREDIT_CARD_VERIFICATION_CODE,
COMPANY_NAME,
Expand Down
4 changes: 3 additions & 1 deletion components/autofill/core/browser/form_parsing/form_field.cc
Expand Up @@ -32,6 +32,7 @@
#include "components/autofill/core/browser/form_parsing/phone_field.h"
#include "components/autofill/core/browser/form_parsing/price_field.h"
#include "components/autofill/core/browser/form_parsing/search_field.h"
#include "components/autofill/core/browser/form_parsing/standalone_cvc_field.h"
#include "components/autofill/core/browser/form_parsing/travel_field.h"
#include "components/autofill/core/browser/form_processing/autocomplete_attribute_processing_util.h"
#include "components/autofill/core/browser/form_structure.h"
Expand Down Expand Up @@ -508,7 +509,8 @@ bool FormField::MatchesFormControlType(base::StringPiece type,

// static
bool FormField::IsSingleFieldParseableType(ServerFieldType field_type) {
return field_type == MERCHANT_PROMO_CODE || field_type == IBAN_VALUE;
return field_type == MERCHANT_PROMO_CODE || field_type == IBAN_VALUE ||
field_type == CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
}

// static
Expand Down
@@ -0,0 +1,80 @@
// Copyright 2022 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.

#include "components/autofill/core/browser/form_parsing/standalone_cvc_field.h"

#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_regex_constants.h"
#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/common/autofill_payments_features.h"

namespace autofill {

// static
std::unique_ptr<FormField> StandaloneCvcField::Parse(
AutofillScanner* scanner,
const LanguageCode& page_language,
PatternSource pattern_source,
LogManager* log_manager) {
if (!base::FeatureList::IsEnabled(
features::kAutofillParseVcnCardOnFileStandaloneCvcFields)) {
return nullptr;
}

// Ignore gift card fields as both |kGiftCardRe| and |kCardCvcRe| matches
// "gift card pin" and "gift card code" but it should only match
// |kGiftCardRe|.
if (MatchGiftCard(scanner, log_manager, page_language, pattern_source)) {
return nullptr;
}

AutofillField* field;
base::span<const MatchPatternRef> cvc_patterns = GetMatchPatterns(
CREDIT_CARD_VERIFICATION_CODE, page_language, pattern_source);

// CVC fields can occur in many different field types so we check for each
const auto kMatchNumTelAndPwd =
kDefaultMatchParamsWith<MatchFieldType::kNumber,
MatchFieldType::kTelephone,
MatchFieldType::kPassword>;
if (ParseFieldSpecifics(scanner, kCardCvcRe, kMatchNumTelAndPwd, cvc_patterns,
&field, {log_manager, "kCardCvcRe(standalone)"})) {
return std::make_unique<StandaloneCvcField>(field);
}

return nullptr;
}

StandaloneCvcField::~StandaloneCvcField() = default;

// static
bool StandaloneCvcField::MatchGiftCard(AutofillScanner* scanner,
LogManager* log_manager,
const LanguageCode& page_language,
PatternSource pattern_source) {
if (scanner->IsEnd())
return false;

const auto kMatchFieldType = kDefaultMatchParamsWith<
MatchFieldType::kNumber, MatchFieldType::kTelephone,
MatchFieldType::kSearch, MatchFieldType::kPassword>;
base::span<const MatchPatternRef> gift_card_patterns =
GetMatchPatterns("GIFT_CARD", page_language, pattern_source);

return ParseFieldSpecifics(scanner, kGiftCardRe, kMatchFieldType,
gift_card_patterns, nullptr,
{log_manager, "kGiftCardRe"});
}

StandaloneCvcField::StandaloneCvcField(const AutofillField* field)
: field_(field) {}

void StandaloneCvcField::AddClassifications(
FieldCandidatesMap& field_candidates) const {
AddClassification(field_, CREDIT_CARD_STANDALONE_VERIFICATION_CODE,
kBaseCreditCardParserScore, field_candidates);
}

} // namespace autofill
@@ -0,0 +1,50 @@
// Copyright 2022 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_AUTOFILL_CORE_BROWSER_FORM_PARSING_STANDALONE_CVC_FIELD_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_STANDALONE_CVC_FIELD_H_

#include <memory>

#include "base/memory/raw_ptr.h"
#include "components/autofill/core/browser/form_parsing/form_field.h"
#include "components/autofill/core/common/language_code.h"

namespace autofill {

class AutofillField;
class AutofillScanner;
class LogManager;

// A form field that accepts a standalone cvc.
class StandaloneCvcField : public FormField {
public:
static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
const LanguageCode& page_language,
PatternSource pattern_source,
LogManager* log_manager);

explicit StandaloneCvcField(const AutofillField* field);

~StandaloneCvcField() override;

StandaloneCvcField(const StandaloneCvcField&) = delete;
StandaloneCvcField& operator=(const StandaloneCvcField&) = delete;

protected:
void AddClassifications(FieldCandidatesMap& field_candidates) const override;

private:
raw_ptr<const AutofillField> field_;

// static
static bool MatchGiftCard(AutofillScanner* scanner,
LogManager* log_manager,
const LanguageCode& page_language,
PatternSource pattern_source);
};

} // namespace autofill

#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_STANDALONE_CVC_FIELD_H_
@@ -0,0 +1,78 @@
// Copyright 2022 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.

#include "components/autofill/core/browser/form_parsing/standalone_cvc_field.h"

#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
#include "components/autofill/core/common/autofill_payments_features.h"

namespace autofill {

class StandaloneCvcFieldTest
: public FormFieldTestBase,
public testing::TestWithParam<PatternProviderFeatureState> {
public:
StandaloneCvcFieldTest() : FormFieldTestBase(GetParam()) {}
StandaloneCvcFieldTest(const StandaloneCvcFieldTest&) = delete;
StandaloneCvcFieldTest& operator=(const StandaloneCvcFieldTest&) = delete;

protected:
std::unique_ptr<FormField> Parse(
AutofillScanner* scanner,
const LanguageCode& page_language = LanguageCode("en")) override {
return StandaloneCvcField::Parse(scanner, page_language,
GetActivePatternSource(),
/*log_manager=*/nullptr);
}

base::test::ScopedFeatureList scoped_feature_list_;
};

INSTANTIATE_TEST_SUITE_P(
StandaloneCvcFieldTest,
StandaloneCvcFieldTest,
::testing::ValuesIn(PatternProviderFeatureState::All()));

// Match standalone cvc.
TEST_P(StandaloneCvcFieldTest, ParseStandaloneCvc) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillParseVcnCardOnFileStandaloneCvcFields);

AddTextFormFieldData("cvc", "CVC:", CREDIT_CARD_STANDALONE_VERIFICATION_CODE);

ClassifyAndVerify(ParseResult::PARSED);
}

// Do not parse non cvc standalone fields.
TEST_P(StandaloneCvcFieldTest, ParseNonStandaloneCvc) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillParseVcnCardOnFileStandaloneCvcFields);

AddTextFormFieldData("other-field", "Other Field:", UNKNOWN_TYPE);

ClassifyAndVerify(ParseResult::NOT_PARSED);
}

// Do not parse when standalone cvc flag is disabled.
TEST_P(StandaloneCvcFieldTest, ParseStandaloneCvcFlagOff) {
scoped_feature_list_.InitAndDisableFeature(
features::kAutofillParseVcnCardOnFileStandaloneCvcFields);

AddTextFormFieldData("cvc", "CVC:", CREDIT_CARD_STANDALONE_VERIFICATION_CODE);

ClassifyAndVerify(ParseResult::NOT_PARSED);
}

// Do not parse gift card as standalone cvc fields.
TEST_P(StandaloneCvcFieldTest, NotParseGiftCardAsStandaloneCvc) {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillParseVcnCardOnFileStandaloneCvcFields);

AddTextFormFieldData("gift-card", "Gift Card Pin:", UNKNOWN_TYPE);

ClassifyAndVerify(ParseResult::NOT_PARSED);
}

} // namespace autofill
Expand Up @@ -377,6 +377,7 @@ int GetFieldTypeGroupPredictionQualityMetric(
case BIRTHDATE_4_DIGIT_YEAR:
case IBAN_VALUE:
case MAX_VALID_FIELD_TYPE:
case CREDIT_CARD_STANDALONE_VERIFICATION_CODE:
NOTREACHED() << field_type << " type is not in that group.";
group = GROUP_AMBIGUOUS;
break;
Expand Down
Expand Up @@ -96,7 +96,8 @@ TEST(AutofillShadowPredictionComparisonTest, ComparisonContainsAllTypes) {
// If this test fails after adding a type, update
// `AutofillPredictionsComparisonResult` in tools/metrics/histograms/enums.xml
// and set `last_known_type` to the last entry in the enum.
constexpr ServerFieldType last_known_type = IBAN_VALUE;
constexpr ServerFieldType last_known_type =
CREDIT_CARD_STANDALONE_VERIFICATION_CODE;
int max_comparison =
GetShadowPrediction(last_known_type, NAME_FIRST, {NAME_LAST});

Expand Down
18 changes: 18 additions & 0 deletions tools/metrics/histograms/enums.xml
Expand Up @@ -9104,6 +9104,24 @@ others/histograms.xml -->
<int value="756"
label="IBAN_VALUE - Predictions different - Value agrees with both
predictions"/>
<int value="757"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions equal -
Value agrees"/>
<int value="758"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions equal -
Value disagrees"/>
<int value="759"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions different
- Value agrees with old prediction"/>
<int value="760"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions different
- Value agrees with new prediction"/>
<int value="761"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions different
- Value agrees with neither prediction"/>
<int value="762"
label="CREDIT_CARD_STANDALONE_VERIFICATION_CODE - Predictions different
- Value agrees with both predictions"/>
</enum>

<enum name="AutofillPredictionSource">
Expand Down

0 comments on commit 8597763

Please sign in to comment.