Bug 1169290 - Add navigator.webdriver attribute. r?bz,maja_zf draft
authorAndreas Tolfsen <ato@sny.no>
Sat, 27 Jan 2018 19:42:17 +0000
changeset 753898 9a6c619f6f3390750efa286162f461c0e0192d1c
parent 753897 c2ce4da729c2f9acc429b9d840d49aa97cfa519b
child 753899 ac2ca0f234a2268b68420caf876c84331f9017e6
push id98715
push userbmo:ato@sny.no
push dateMon, 12 Feb 2018 16:37:16 +0000
reviewersbz, maja_zf
bugs1169290
milestone60.0a1
Bug 1169290 - Add navigator.webdriver attribute. r?bz,maja_zf This patch adds an enumerable, configurable, readonly attribute "webdriver" to the Navigator object. The attribute is true when the -marionette flag has been passed to Firefox or the marionette.enabled preference is true. Otherwise it is false. The definition of the interface is found in the WebDriver standard: https://w3c.github.io/webdriver/webdriver-spec.html#interface The navigator.webdriver attribute is meant as an indication to web authors that a document is visited by WebDriver. It is important to stress that it is not meant as a fool-proof way to detect that a website is being visited by a browser automation tool, but as a tool for web documents to take alternate code paths. MozReview-Commit-ID: D3qXVKqZG
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/webidl/Navigator.webidl
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/webdriver/tests/interface.html.ini
testing/web-platform/tests/webdriver/tests/interface.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1882,10 +1882,17 @@ CredentialsContainer*
 Navigator::Credentials()
 {
   if (!mCredentials) {
     mCredentials = new CredentialsContainer(GetWindow());
   }
   return mCredentials;
 }
 
+/* static */
+bool
+Navigator::Webdriver()
+{
+  return Preferences::GetBool("marionette.enabled", false);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -196,16 +196,18 @@ public:
                               uint64_t aInnerWindowID,
                               const nsAString& aCallID,
                               ErrorResult& aRv);
 
   already_AddRefed<ServiceWorkerContainer> ServiceWorker();
 
   mozilla::dom::CredentialsContainer* Credentials();
 
+  static bool Webdriver();
+
   void GetLanguages(nsTArray<nsString>& aLanguages);
 
   StorageManager* Storage();
 
   static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
 
   // WebIDL helper methods
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -10,16 +10,17 @@
  * http://www.w3.org/TR/battery-status/#navigatorbattery-interface
  * http://www.w3.org/TR/vibration/#vibration-interface
  * http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1
  * https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
  * http://www.w3.org/TR/beacon/#sec-beacon-method
  * https://html.spec.whatwg.org/#navigatorconcurrenthardware
  * http://wicg.github.io/netinfo/#extensions-to-the-navigator-interface
  * https://w3c.github.io/webappsec-credential-management/#framework-credential-management
+ * https://w3c.github.io/webdriver/webdriver-spec.html#interface
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
 [HeaderFile="Navigator.h"]
@@ -28,16 +29,17 @@ interface Navigator {
 };
 Navigator implements NavigatorID;
 Navigator implements NavigatorLanguage;
 Navigator implements NavigatorOnLine;
 Navigator implements NavigatorContentUtils;
 Navigator implements NavigatorStorageUtils;
 Navigator implements NavigatorConcurrentHardware;
 Navigator implements NavigatorStorage;
+Navigator implements NavigatorAutomationInformation;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface NavigatorID {
   // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
   [Constant, Cached, Throws]
   readonly attribute DOMString appCodeName; // constant "Mozilla"
   [Constant, Cached, NeedsCallerType]
   readonly attribute DOMString appName;
@@ -303,8 +305,14 @@ interface NavigatorConcurrentHardware {
   readonly attribute unsigned long long hardwareConcurrency;
 };
 
 // https://w3c.github.io/webappsec-credential-management/#framework-credential-management
 partial interface Navigator {
   [Pref="security.webauth.webauthn", SecureContext, SameObject]
   readonly attribute CredentialsContainer credentials;
 };
+
+// https://w3c.github.io/webdriver/webdriver-spec.html#interface
+[NoInterfaceObject]
+interface NavigatorAutomationInformation {
+  readonly attribute boolean webdriver;
+};
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -592244,29 +592244,29 @@
    "d589b53f0096893600e696b43ec19ca84e5ee2ab",
    "wdspec"
   ],
   "webdriver/tests/actions/key_shortcuts.py": [
    "dbe27dd0b1625169fc8cc2055f8fb49d5a4a78d2",
    "wdspec"
   ],
   "webdriver/tests/actions/modifier_click.py": [
-   "56df38086ef05cd8bff1437038efb598ab63f1e3",
+   "88a384182fdd9df1515b9d8cfda8f56aed138ec7",
    "wdspec"
   ],
   "webdriver/tests/actions/mouse.py": [
-   "2fb4c47335f144a2dd6f16db4c20239116f20fed",
+   "edad7693fcd01b418821942edb870191db64ea41",
    "wdspec"
   ],
   "webdriver/tests/actions/mouse_dblclick.py": [
-   "932b053eef5e052d53ab2007540428d68b758ad4",
+   "f6afcb8c0fa017d58a9fcdd3cc474e0c8fd52db5",
    "wdspec"
   ],
   "webdriver/tests/actions/pointer_origin.py": [
-   "da2a9f21018582c8cd52d206d172841f71fd19f3",
+   "a9a99d58daec7719ee53ed758f566ccceb582f65",
    "wdspec"
   ],
   "webdriver/tests/actions/sequence.py": [
    "d43caf0f8607a76c3baed7806664b686bde21fda",
    "wdspec"
   ],
   "webdriver/tests/actions/special_keys.py": [
    "64eb2401664b71d68f7b53e236a947eec6d651cc",
@@ -592276,25 +592276,25 @@
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
   "webdriver/tests/actions/support/keys.py": [
    "528ab8473914c14f9671d89b8a888d30162714ec",
    "support"
   ],
   "webdriver/tests/actions/support/mouse.py": [
-   "208a1c4fbc0d5c542d17de7f6474d477ce1feb45",
+   "bc7da107e5b897105dfa7405aa57cba7355854dc",
    "support"
   ],
   "webdriver/tests/actions/support/refine.py": [
    "0d244bffe67ef57be68aad99f1cbc7440ff80e27",
    "support"
   ],
   "webdriver/tests/actions/support/test_actions_wdspec.html": [
-   "34f99c46ac9c52e5902477c26a3d16a89a29235a",
+   "95203777fcc012ab64465287737a89a4ba2c31dc",
    "support"
   ],
   "webdriver/tests/conftest.py": [
    "c812269d034c9ca1b8c4f136dd5d0cea52f4d0f0",
    "support"
   ],
   "webdriver/tests/contexts/json_serialize_windowproxy.py": [
    "d29c82c48b3bd1e2b07c40798a774eb77d6178a5",
@@ -592412,17 +592412,17 @@
    "7d0a8199890afb97894c363af7ef342b5ed5cef3",
    "wdspec"
   ],
   "webdriver/tests/interaction/send_keys_content_editable.py": [
    "9c071e60e1203cf31120f20874b5f38ba41dacc3",
    "wdspec"
   ],
   "webdriver/tests/interface.html": [
-   "6625887cfa7f461dc428c11861fce71c47bef57d",
+   "f7b2c45ff8b1b5790dd390fbe2ab997766f5d9a8",
    "testharness"
   ],
   "webdriver/tests/minimize_window.py": [
    "ac1df5462702ac368ffa92cc12cfb5e34df226ac",
    "wdspec"
   ],
   "webdriver/tests/navigation/current_url.py": [
    "828e40301838c99aa2978733bbce3db3acc185a0",
deleted file mode 100644
--- a/testing/web-platform/meta/webdriver/tests/interface.html.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[interface.html]
-  [Navigator interface: attribute webdriver]
-    expected: FAIL
-
-  [Navigator interface: navigator must inherit property "webdriver" with the proper type (0)]
-    expected: FAIL
-
-  [Navigator interface: navigator must inherit property "webdriver" with the proper type]
-    expected: FAIL
-
--- a/testing/web-platform/tests/webdriver/tests/interface.html
+++ b/testing/web-platform/tests/webdriver/tests/interface.html
@@ -1,38 +1,49 @@
-<!DOCTYPE html>
-<body>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
+<!doctype html>
+<meta charset=utf-8>
+
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
 <script src=/resources/WebIDLParser.js></script>
 <script src=/resources/idlharness.js></script>
+
 <script type=text/plain class=untested>
 [Exposed=Window]
 interface Navigator {
   // objects implementing this interface also implement the interfaces given below
 };
 </script>
+
 <script type=text/plain>
 Navigator includes NavigatorAutomationInformation;
 
 interface mixin NavigatorAutomationInformation {
-    readonly attribute boolean webdriver;
-    // always returns true
+  readonly attribute boolean webdriver;
 };
 </script>
+
 <script>
 "use strict";
 
-if ("webdriver" in navigator) {
-  test(() => assert_true(navigator.webdriver), "navigator.webdriver is always true");
-  var idlArray = new IdlArray();
-  [].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
-    if (node.className == "untested") {
-      idlArray.add_untested_idls(node.textContent);
-    } else {
-      idlArray.add_idls(node.textContent);
-    }
-  });
-  idlArray.test();
-} else {
-  done();
+test(() => assert_idl_attribute(navigator, "webdriver"), "navigator.webdriver is present");
+
+// When test is run in automation navigator.webdriver is likely to
+// be true because WebDriver controls the browser instance.  To that
+// extent, this test is a bit special.  It should also be possible to
+// run the test manually, when WebDriver is not active, and so either
+// true/false outcome is OK.
+if (navigator.webdriver) {
+  test(() => assert_true(navigator.webdriver), "navigator.webdriver is true when webdriver-active is set");
+} else {
+  test(() => assert_false(navigator.webdriver), "navigator.webdriver is false when webdriver-active is not set");
 }
+
+var idls = new IdlArray();
+for (let node of [...document.scripts].filter(({type}) => type == "text/plain")) {
+  if (node.className == "untested") {
+    idls.add_untested_idls(node.textContent);
+  } else {
+    idls.add_idls(node.textContent);
+  }
+};
+idls.test();
 </script>