Bug 1413487 - [Form Autofill] Split "cc-exp" into "cc-exp-month" and "cc-exp-year" in the storage. r=seanlee
authorLuke Chang <lchang@mozilla.com>
Thu, 02 Nov 2017 12:19:22 +0800
changeset 443733 1fe74041cd1cfc3f12e0b1f05894cb26c61a8fef
parent 443732 2ee4a30d1ea7b08a38ff5108ee6055a337046e68
child 443734 c2b1d6f40e476383dd55caeb8c1ce3f946b2855d
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseanlee
bugs1413487
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1413487 - [Form Autofill] Split "cc-exp" into "cc-exp-month" and "cc-exp-year" in the storage. r=seanlee MozReview-Commit-ID: 1JKJFudYWHb
browser/extensions/formautofill/ProfileStorage.jsm
browser/extensions/formautofill/test/unit/test_transformFields.js
--- 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",
     },