Bug 1477798 - Treat sensitive @autocomplete field names like 'off' in satchel. r=Felipe
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Thu, 10 Jan 2019 18:49:10 +0000
changeset 510424 b9002ded5523510c9926c5450bf101d7cbd0be07
parent 510423 8ba84058447350628db3f23906674e681ff2c927
child 510425 c334bf626b6d9366dc5a6d5d6deae9caa276bcea
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersFelipe
bugs1477798
milestone66.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 1477798 - Treat sensitive @autocomplete field names like 'off' in satchel. r=Felipe This also has the side-effect of fixing autocomplete parsing for 'off' to ignore whitespace: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-processing-model Differential Revision: https://phabricator.services.mozilla.com/D15779
toolkit/components/satchel/formSubmitListener.js
toolkit/components/satchel/test/test_form_submission.html
--- a/toolkit/components/satchel/formSubmitListener.js
+++ b/toolkit/components/satchel/formSubmitListener.js
@@ -87,19 +87,19 @@ let satchelFormListener = {
         // that allow the user to toggle password visibility.
         if (input.hasBeenTypePassword) {
           continue;
         }
 
         // Bug 394612: If Login Manager marked this input, don't save it.
         // The login manager will deal with remembering it.
 
-        // Don't save values when autocomplete=off is present.
-        if (input.hasAttribute("autocomplete") &&
-          input.getAttribute("autocomplete").toLowerCase() == "off") {
+        // Don't save values when @autocomplete is "off" or has a sensitive field name.
+        let autocompleteInfo = input.getAutocompleteInfo();
+        if (autocompleteInfo && !autocompleteInfo.canAutomaticallyPersist) {
           continue;
         }
 
         let value = input.value.trim();
 
         // Don't save empty or unchanged values.
         if (!value || value == input.defaultValue.trim()) {
           continue;
--- a/toolkit/components/satchel/test/test_form_submission.html
+++ b/toolkit/components/satchel/test/test_form_submission.html
@@ -8,24 +8,24 @@
 </head>
 <body>
 <p id="display"></p>
 <iframe id="iframe" src="https://example.com/tests/toolkit/components/satchel/test/subtst_form_submission_1.html"></iframe>
 <div id="content" style="display: none">
 
   <!-- ===== Things that should not be saved. ===== -->
 
-  <!-- autocomplete=off for input -->
+  <!-- autocomplete=off (case-insensitive token) for input -->
   <form id="form1" onsubmit="return checkSubmit(1)">
-    <input type="text" name="test1" autocomplete="off">
+    <input type="text" name="test1" autocomplete=" oFf ">
     <button type="submit">Submit</button>
   </form>
 
   <!-- autocomplete=off for form -->
-  <form id="form2" onsubmit="return checkSubmit(2)" autocomplete="off">
+  <form id="form2" onsubmit="return checkSubmit(2)" autocomplete="oFf">
     <input type="text" name="test1">
     <button type="submit">Submit</button>
   </form>
 
   <!-- don't save type=hidden -->
   <form id="form3" onsubmit="return checkSubmit(3)">
     <input type="hidden" name="test1">
     <button type="submit">Submit</button>
@@ -156,16 +156,28 @@
   </form>
 
   <!-- Don't save values if the input name is 'searchbar-history' -->
   <form id="form22" onsubmit="return checkSubmit(22);">
     <input type='text' name='searchbar-history'>
     <button type='submit'>Submit</button>
   </form>
 
+  <!-- autocomplete=cc-csc (case-insensitive token) for input -->
+  <form id="form23" onsubmit="return checkSubmit(23)">
+    <input type="text" name="test1" autocomplete="  cc-CSC  ">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- autocomplete=new-password (case-insensitive token) for input -->
+  <form id="form24" onsubmit="return checkSubmit(24)">
+    <input type="text" name="test1" autocomplete="  NEW-password  ">
+    <button type="submit">Submit</button>
+  </form>
+
   <!-- ===== Things that should be saved ===== -->
 
   <!-- Form 100 is submitted into an iframe, not declared here. -->
 
   <!-- input with no default value -->
   <form id="form101" onsubmit="return checkSubmit(101)">
     <input type="text" name="test1">
     <button type="submit">Submit</button>
@@ -325,16 +337,18 @@ function startTest() {
     $_(16, "test" + (i + 1)).value = testData[i];
   }
   $_(17, "test1").value = "6799990100000000019";
   $_(18, "test1").value = "0000-0000-0080-4609";
   $_(19, "test1").value = "0000 0000 0222 331";
   $_(20, "test1").value = "dontSaveThis";
   $_(21, "test1").value = "dontSaveThis";
   $_(22, "searchbar-history").value = "dontSaveThis";
+  $_(23, "test1").value = "987";
+  $_(24, "test1").value = "s3cr3t";
 
   $_(101, "test1").value = "savedValue";
   $_(102, "test2").value = "savedValue";
   $_(103, "test3").value = "savedValue";
   $_(104, "test4").value = " trimTrailingAndLeadingSpace ";
   $_(105, "test5").value = "\t trimTrailingAndLeadingWhitespace\t ";
   $_(106, "test6").value = "55555555555544445553"; // passes luhn but too long
 
@@ -382,16 +396,18 @@ function checkSubmit(formNum) {
     case 15:
     case 16:
     case 17:
     case 18:
     case 19:
     case 20:
     case 21:
     case 22:
+    case 23:
+    case 24:
       countEntries(null, null,
                    function(num) {
                      ok(!num, "checking for empty storage");
                      submitForm(formNum);
                    });
       return false;
     case 100:
       checkForSave("subtest2", "subtestValue", "checking saved subtest value");
@@ -447,33 +463,33 @@ function submitForm(formNum) {
     // finish(), yet let the test actually end first, to be safe.
     SimpleTest.executeSoon(SimpleTest.finish);
 
     return false; // return false to cancel current form submission
   }
 
   // End the test at the last form.
   if (formNum == 109) {
-    is(numSubmittedForms, 32, "Ensuring all forms were submitted.");
+    is(numSubmittedForms, 34, "Ensuring all forms were submitted.");
     checkObserver.uninit();
     SimpleTest.executeSoon(SimpleTest.finish);
     return false; // return false to cancel current form submission
   }
 
   // This timeout is here so that button.click() is never called before this
   // function returns. If button.click() is called before returning, a long
   // chain of submits will happen recursively since the submit is dispatched
   // immediately.
   //
   // This in itself is fine, but if there are errors in the code, mochitests
   // will in some cases give you "server too busy", which is hard to debug!
   //
   setTimeout(function() {
     checkObserver.waitForChecks(function() {
-      let nextFormNum = formNum == 22 ? 100 : (formNum + 1);
+      let nextFormNum = formNum == 24 ? 100 : (formNum + 1);
 
       // Submit the next form. Special cases are Forms 21 and 100, which happen
       // from an HTTPS domain in an iframe.
       if (nextFormNum == 100) {
         ok(true, "submitting iframe test " + nextFormNum);
         SpecialPowers.wrap(document.getElementById("iframe").contentWindow)
         .wrappedJSObject.clickButton(nextFormNum);
       } else {