--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -1519,51 +1519,116 @@ class CreditCards extends AutofillRecord
_stripComputedFields(creditCard) {
if (creditCard["cc-number-encrypted"]) {
creditCard["cc-number"] = MasterPassword.decryptSync(creditCard["cc-number-encrypted"]);
}
super._stripComputedFields(creditCard);
}
_normalizeFields(creditCard) {
- // Normalize name
+ this._normalizeCCName(creditCard);
+ this._normalizeCCExpirationDate(creditCard);
+ }
+
+ _normalizeCCName(creditCard) {
if (creditCard["cc-given-name"] || creditCard["cc-additional-name"] || creditCard["cc-family-name"]) {
if (!creditCard["cc-name"]) {
creditCard["cc-name"] = FormAutofillNameUtils.joinNameParts({
given: creditCard["cc-given-name"],
middle: creditCard["cc-additional-name"],
family: creditCard["cc-family-name"],
});
}
delete creditCard["cc-given-name"];
delete creditCard["cc-additional-name"];
delete creditCard["cc-family-name"];
}
+ }
- // Validate expiry date
+ _normalizeCCExpirationDate(creditCard) {
if (creditCard["cc-exp-month"]) {
let expMonth = parseInt(creditCard["cc-exp-month"], 10);
if (isNaN(expMonth) || expMonth < 1 || expMonth > 12) {
delete creditCard["cc-exp-month"];
} else {
creditCard["cc-exp-month"] = expMonth;
}
}
+
if (creditCard["cc-exp-year"]) {
let expYear = parseInt(creditCard["cc-exp-year"], 10);
if (isNaN(expYear) || expYear < 0) {
delete creditCard["cc-exp-year"];
} else if (expYear < 100) {
// Enforce 4 digits years.
creditCard["cc-exp-year"] = expYear + 2000;
} else {
creditCard["cc-exp-year"] = expYear;
}
}
+
+ if (creditCard["cc-exp"] && (!creditCard["cc-exp-month"] || !creditCard["cc-exp-year"])) {
+ let rules = [
+ {
+ regex: "(\\d{4})[-/](\\d{1,2})",
+ yearIndex: 1,
+ monthIndex: 2,
+ },
+ {
+ regex: "(\\d{1,2})[-/](\\d{4})",
+ yearIndex: 2,
+ monthIndex: 1,
+ },
+ {
+ regex: "(\\d{1,2})[-/](\\d{1,2})",
+ },
+ {
+ regex: "(\\d{2})(\\d{2})",
+ },
+ ];
+
+ for (let rule of rules) {
+ let result = new RegExp(`(?:^|\\D)${rule.regex}(?!\\d)`).exec(creditCard["cc-exp"]);
+ if (!result) {
+ continue;
+ }
+
+ let expYear, expMonth;
+
+ if (!rule.yearIndex || !rule.monthIndex) {
+ expMonth = parseInt(result[1], 10);
+ if (expMonth > 12) {
+ expYear = parseInt(result[1], 10);
+ expMonth = parseInt(result[2], 10);
+ } else {
+ expYear = parseInt(result[2], 10);
+ }
+ } else {
+ expYear = parseInt(result[rule.yearIndex], 10);
+ expMonth = parseInt(result[rule.monthIndex], 10);
+ }
+
+ if (expMonth < 1 || expMonth > 12) {
+ continue;
+ }
+
+ if (expYear < 100) {
+ expYear += 2000;
+ } else if (expYear < 2000) {
+ continue;
+ }
+
+ creditCard["cc-exp-month"] = expMonth;
+ creditCard["cc-exp-year"] = expYear;
+ break;
+ }
+ }
+
+ delete creditCard["cc-exp"];
}
}
function ProfileStorage(path) {
this._path = path;
this._initializePromise = null;
this.INTERNAL_FIELDS = INTERNAL_FIELDS;
}
--- a/browser/extensions/formautofill/test/unit/test_transformFields.js
+++ b/browser/extensions/formautofill/test/unit/test_transformFields.js
@@ -522,46 +522,241 @@ const CREDIT_CARD_COMPUTE_TESTCASES = [
},
];
const CREDIT_CARD_NORMALIZE_TESTCASES = [
// Empty
{
description: "No normalizable field",
creditCard: {
- "cc-number": "1234123412341234", // cc-number won't be verified
},
expectedResult: {
},
},
// Name
{
description: "Has both \"cc-name\" and the split name fields",
creditCard: {
"cc-name": "Timothy John Berners-Lee",
"cc-given-name": "John",
"cc-family-name": "Doe",
- "cc-number": "1234123412341234", // cc-number won't be verified
},
expectedResult: {
"cc-name": "Timothy John Berners-Lee",
},
},
{
description: "Has only the split name fields",
creditCard: {
"cc-given-name": "John",
"cc-family-name": "Doe",
- "cc-number": "1234123412341234", // cc-number won't be verified
},
expectedResult: {
"cc-name": "John Doe",
},
},
+
+ // Expiration Date
+ {
+ description: "Has \"cc-exp\" formatted \"yyyy-mm\"",
+ creditCard: {
+ "cc-exp": "2022-12",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yyyy/mm\"",
+ creditCard: {
+ "cc-exp": "2022/12",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yyyy-m\"",
+ creditCard: {
+ "cc-exp": "2022-3",
+ },
+ expectedResult: {
+ "cc-exp-month": 3,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yyyy/m\"",
+ creditCard: {
+ "cc-exp": "2022/3",
+ },
+ expectedResult: {
+ "cc-exp-month": 3,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"mm-yyyy\"",
+ creditCard: {
+ "cc-exp": "12-2022",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"mm/yyyy\"",
+ creditCard: {
+ "cc-exp": "12/2022",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"m-yyyy\"",
+ creditCard: {
+ "cc-exp": "3-2022",
+ },
+ expectedResult: {
+ "cc-exp-month": 3,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"m/yyyy\"",
+ creditCard: {
+ "cc-exp": "3/2022",
+ },
+ expectedResult: {
+ "cc-exp-month": 3,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"mm-yy\"",
+ creditCard: {
+ "cc-exp": "12-22",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"mm/yy\"",
+ creditCard: {
+ "cc-exp": "12/22",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yy-mm\"",
+ creditCard: {
+ "cc-exp": "22-12",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yy/mm\"",
+ creditCard: {
+ "cc-exp": "22/12",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"mmyy\"",
+ creditCard: {
+ "cc-exp": "1222",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" formatted \"yymm\"",
+ creditCard: {
+ "cc-exp": "2212",
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has \"cc-exp\" with spaces",
+ creditCard: {
+ "cc-exp": " 2033-11 ",
+ },
+ expectedResult: {
+ "cc-exp-month": 11,
+ "cc-exp-year": 2033,
+ },
+ },
+ {
+ description: "Has invalid \"cc-exp\"",
+ creditCard: {
+ "cc-exp": "99-9999",
+ },
+ expectedResult: {
+ "cc-exp-month": undefined,
+ "cc-exp-year": undefined,
+ },
+ },
+ {
+ description: "Has both \"cc-exp-*\" and \"cc-exp\"",
+ creditCard: {
+ "cc-exp": "2022-12",
+ "cc-exp-month": 3,
+ "cc-exp-year": 2030,
+ },
+ expectedResult: {
+ "cc-exp-month": 3,
+ "cc-exp-year": 2030,
+ },
+ },
+ {
+ description: "Has only \"cc-exp-year\" and \"cc-exp\"",
+ creditCard: {
+ "cc-exp": "2022-12",
+ "cc-exp-year": 2030,
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+ {
+ description: "Has only \"cc-exp-month\" and \"cc-exp\"",
+ creditCard: {
+ "cc-exp": "2022-12",
+ "cc-exp-month": 3,
+ },
+ expectedResult: {
+ "cc-exp-month": 12,
+ "cc-exp-year": 2022,
+ },
+ },
+
+ // Card Number
{
description: "Number should be encrypted and masked",
creditCard: {
"cc-number": "1234123412341234",
},
expectedResult: {
"cc-number": "************1234",
},