Bug 1298370 - Add SameSite attribute to Cookie Inspector r+pbrosset draft
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Thu, 01 Dec 2016 17:11:31 +0000
changeset 451030 7db81a87960e0eafc3571663e5517ee9de0f468e
parent 450924 863c2b61bd27bb6099104933134d3be7c052551a
child 539904 a3fbba304d74a7a31d5b251e055a1b45c7a48f51
push id39029
push userbmo:mratcliffe@mozilla.com
push dateMon, 19 Dec 2016 13:26:55 +0000
bugs1298370
milestone53.0a1
Bug 1298370 - Add SameSite attribute to Cookie Inspector r+pbrosset MozReview-Commit-ID: 3HcVmGiZZEg
devtools/client/locales/en-US/storage.properties
devtools/client/storage/test/browser.ini
devtools/client/storage/test/browser_storage_cookies_samesite.js
devtools/client/storage/test/storage-cookies-samesite.html
devtools/server/actors/storage.js
--- a/devtools/client/locales/en-US/storage.properties
+++ b/devtools/client/locales/en-US/storage.properties
@@ -38,16 +38,17 @@ tree.labels.Cache=Cache Storage
 table.headers.cookies.uniqueKey=Unique key
 table.headers.cookies.name=Name
 table.headers.cookies.path=Path
 table.headers.cookies.host=Domain
 table.headers.cookies.expires=Expires on
 table.headers.cookies.value=Value
 table.headers.cookies.lastAccessed=Last accessed on
 table.headers.cookies.creationTime=Created on
+table.headers.cookies.sameSite=sameSite
 
 table.headers.localStorage.name=Key
 table.headers.localStorage.value=Value
 
 table.headers.sessionStorage.name=Key
 table.headers.sessionStorage.value=Value
 
 table.headers.Cache.url=URL
--- a/devtools/client/storage/test/browser.ini
+++ b/devtools/client/storage/test/browser.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   storage-cache-error.html
   storage-complex-values.html
   storage-cookies.html
+  storage-cookies-samesite.html
   storage-empty-objectstores.html
   storage-idb-delete-blocked.html
   storage-indexeddb-duplicate-names.html
   storage-listings.html
   storage-localstorage.html
   storage-overflow.html
   storage-search.html
   storage-secured-iframe.html
@@ -21,16 +22,17 @@ support-files =
 
 [browser_storage_basic.js]
 [browser_storage_cache_delete.js]
 [browser_storage_cache_error.js]
 [browser_storage_cookies_delete_all.js]
 [browser_storage_cookies_domain.js]
 [browser_storage_cookies_edit.js]
 [browser_storage_cookies_edit_keyboard.js]
+[browser_storage_cookies_samesite.js]
 [browser_storage_cookies_tab_navigation.js]
 [browser_storage_delete.js]
 [browser_storage_delete_all.js]
 [browser_storage_delete_tree.js]
 [browser_storage_dynamic_updates_cookies.js]
 [browser_storage_dynamic_updates_localStorage.js]
 [browser_storage_dynamic_updates_sessionStorage.js]
 [browser_storage_empty_objectstores.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_cookies_samesite.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../framework/test/shared-head.js */
+
+"use strict";
+
+// Test that the samesite cookie attribute is displayed correctly.
+
+add_task(function* () {
+  yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies-samesite.html");
+
+  let id1 = getCookieId("test1", "test1.example.org",
+                        "/browser/devtools/client/storage/test/");
+  let id2 = getCookieId("test2", "test1.example.org",
+                        "/browser/devtools/client/storage/test/");
+  let id3 = getCookieId("test3", "test1.example.org",
+                        "/browser/devtools/client/storage/test/");
+
+  yield checkState([
+    [
+      ["cookies", "test1.example.org"],
+      [ id1, id2, id3 ]
+    ]
+  ]);
+
+  let sameSite1 = getRowValues(id1).sameSite;
+  let sameSite2 = getRowValues(id2).sameSite;
+  let sameSite3 = getRowValues(id3).sameSite;
+
+  is(sameSite1, "Unset", `sameSite1 is "Unset"`);
+  is(sameSite2, "Lax", `sameSite2 is "Lax"`);
+  is(sameSite3, "Strict", `sameSite3 is "Strict"`);
+
+  yield finishTests();
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/storage/test/storage-cookies-samesite.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Storage inspector cookie samesite test</title>
+  </head>
+  <body>
+    <script type="application/javascript;version=1.7">
+    "use strict";
+    let expiresIn24Hours = new Date(Date.now() + 60 * 60 * 24 * 1000).toUTCString();
+
+    document.cookie = "test1=value1;expires=" + expiresIn24Hours + ";";
+    document.cookie = "test2=value2;expires=" + expiresIn24Hours + ";SameSite=lax";
+    document.cookie = "test3=value3;expires=" + expiresIn24Hours + ";SameSite=strict";
+    </script>
+  </body>
+</html>
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -12,16 +12,22 @@ const protocol = require("devtools/share
 const {LongStringActor} = require("devtools/server/actors/string");
 const {DebuggerServer} = require("devtools/server/main");
 const Services = require("Services");
 const promise = require("promise");
 const {isWindowIncluded} = require("devtools/shared/layout/utils");
 const specs = require("devtools/shared/specs/storage");
 const { Task } = require("devtools/shared/task");
 
+// "Lax", "Strict" and "Unset" are special values of the sameSite property
+// that should not be translated.
+const COOKIE_SAMESITE_LAX = "Lax";
+const COOKIE_SAMESITE_STRICT = "Strict";
+const COOKIE_SAMESITE_UNSET = "Unset";
+
 // GUID to be used as a separator in compound keys. This must match the same
 // constant in devtools/client/storage/ui.js,
 // devtools/client/storage/test/head.js and
 // devtools/server/tests/browser/head.js
 const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
 
 loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
 loader.lazyImporter(this, "Sqlite", "resource://gre/modules/Sqlite.jsm");
@@ -494,20 +500,32 @@ StorageActors.createActor({
       // because creationTime is in micro seconds
       creationTime: cookie.creationTime / 1000,
 
       // - do -
       lastAccessed: cookie.lastAccessed / 1000,
       value: new LongStringActor(this.conn, cookie.value || ""),
       isDomain: cookie.isDomain,
       isSecure: cookie.isSecure,
-      isHttpOnly: cookie.isHttpOnly
+      isHttpOnly: cookie.isHttpOnly,
+      sameSite: this.getSameSiteStringFromCookie(cookie)
     };
   },
 
+  getSameSiteStringFromCookie(cookie) {
+    switch (cookie.sameSite) {
+      case cookie.SAMESITE_LAX:
+        return COOKIE_SAMESITE_LAX;
+      case cookie.SAMESITE_STRICT:
+        return COOKIE_SAMESITE_STRICT;
+    }
+    // cookie.SAMESITE_UNSET
+    return COOKIE_SAMESITE_UNSET;
+  },
+
   populateStoresForHost(host) {
     this.hostVsStores.set(host, new Map());
     let doc = this.storageActor.document;
 
     let cookies = this.getCookiesFromHost(host, doc.nodePrincipal
                                                    .originAttributes);
 
     for (let cookie of cookies) {
@@ -607,17 +625,18 @@ StorageActors.createActor({
       { name: "host", editable: true, hidden: false },
       { name: "path", editable: true, hidden: false },
       { name: "expires", editable: true, hidden: false },
       { name: "lastAccessed", editable: false, hidden: false },
       { name: "creationTime", editable: false, hidden: true },
       { name: "value", editable: true, hidden: false },
       { name: "isDomain", editable: false, hidden: true },
       { name: "isSecure", editable: true, hidden: true },
-      { name: "isHttpOnly", editable: true, hidden: false }
+      { name: "isHttpOnly", editable: true, hidden: false },
+      { name: "sameSite", editable: false, hidden: false }
     ];
   }),
 
   /**
    * Pass the editItem command from the content to the chrome process.
    *
    * @param {Object} data
    *        See editCookie() for format details.