summaryrefslogtreecommitdiffstats
path: root/dom/security/featurepolicy/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /dom/security/featurepolicy/test
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/security/featurepolicy/test')
-rw-r--r--dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp162
-rw-r--r--dom/security/featurepolicy/test/gtest/moz.build13
-rw-r--r--dom/security/featurepolicy/test/mochitest/empty.html1
-rw-r--r--dom/security/featurepolicy/test/mochitest/mochitest.toml14
-rw-r--r--dom/security/featurepolicy/test/mochitest/test_featureList.html48
-rw-r--r--dom/security/featurepolicy/test/mochitest/test_parser.html418
-rw-r--r--dom/security/featurepolicy/test/mochitest/test_parser.html^headers^1
7 files changed, 657 insertions, 0 deletions
diff --git a/dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp b/dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp
new file mode 100644
index 0000000000..3e58971c9b
--- /dev/null
+++ b/dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/dom/Feature.h"
+#include "mozilla/dom/FeaturePolicyParser.h"
+#include "nsNetUtil.h"
+#include "nsTArray.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+#define URL_SELF "https://example.com"_ns
+#define URL_EXAMPLE_COM "http://example.com"_ns
+#define URL_EXAMPLE_NET "http://example.net"_ns
+
+void CheckParser(const nsAString& aInput, bool aExpectedResults,
+ uint32_t aExpectedFeatures,
+ nsTArray<Feature>& aParsedFeatures) {
+ nsCOMPtr<nsIPrincipal> principal =
+ mozilla::BasePrincipal::CreateContentPrincipal(URL_SELF);
+ nsTArray<Feature> parsedFeatures;
+ ASSERT_TRUE(FeaturePolicyParser::ParseString(aInput, nullptr, principal,
+ principal, parsedFeatures) ==
+ aExpectedResults);
+ ASSERT_TRUE(parsedFeatures.Length() == aExpectedFeatures);
+
+ aParsedFeatures = std::move(parsedFeatures);
+}
+
+TEST(FeaturePolicyParser, Basic)
+{
+ nsCOMPtr<nsIPrincipal> selfPrincipal =
+ mozilla::BasePrincipal::CreateContentPrincipal(URL_SELF);
+ nsCOMPtr<nsIPrincipal> exampleComPrincipal =
+ mozilla::BasePrincipal::CreateContentPrincipal(URL_EXAMPLE_COM);
+ nsCOMPtr<nsIPrincipal> exampleNetPrincipal =
+ mozilla::BasePrincipal::CreateContentPrincipal(URL_EXAMPLE_NET);
+
+ nsTArray<Feature> parsedFeatures;
+
+ // Empty string is a valid policy.
+ CheckParser(u""_ns, true, 0, parsedFeatures);
+
+ // Empty string with spaces is still valid.
+ CheckParser(u" "_ns, true, 0, parsedFeatures);
+
+ // Non-Existing features with no allowed values
+ CheckParser(u"non-existing-feature"_ns, true, 0, parsedFeatures);
+ CheckParser(u"non-existing-feature;another-feature"_ns, true, 0,
+ parsedFeatures);
+
+ // Existing feature with no allowed values
+ CheckParser(u"camera"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+
+ // Some spaces.
+ CheckParser(u" camera "_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+
+ // A random ;
+ CheckParser(u"camera;"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+
+ // Another random ;
+ CheckParser(u";camera;"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+
+ // 2 features
+ CheckParser(u"camera;microphone"_ns, true, 2, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+ ASSERT_TRUE(parsedFeatures[1].Name().Equals(u"microphone"_ns));
+ ASSERT_TRUE(parsedFeatures[1].HasAllowList());
+
+ // 2 features with spaces
+ CheckParser(u" camera ; microphone "_ns, true, 2, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+ ASSERT_TRUE(parsedFeatures[1].Name().Equals(u"microphone"_ns));
+ ASSERT_TRUE(parsedFeatures[1].HasAllowList());
+
+ // 3 features, but only 2 exist.
+ CheckParser(u"camera;microphone;foobar"_ns, true, 2, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+ ASSERT_TRUE(parsedFeatures[1].Name().Equals(u"microphone"_ns));
+ ASSERT_TRUE(parsedFeatures[1].HasAllowList());
+
+ // Multiple spaces around the value
+ CheckParser(u"camera 'self'"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+
+ // Multiple spaces around the value
+ CheckParser(u"camera 'self' "_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+
+ // No final '
+ CheckParser(u"camera 'self"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+ ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
+
+ // Lowercase/Uppercase
+ CheckParser(u"camera 'selF'"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+
+ // Lowercase/Uppercase
+ CheckParser(u"camera * 'self' none' a.com 123"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowsAll());
+
+ // After a 'none' we don't continue the parsing.
+ CheckParser(u"camera 'none' a.com b.org c.net d.co.uk"_ns, true, 1,
+ parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowsNone());
+
+ // After a * we don't continue the parsing.
+ CheckParser(u"camera * a.com b.org c.net d.co.uk"_ns, true, 1,
+ parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowsAll());
+
+ // 'self'
+ CheckParser(u"camera 'self'"_ns, true, 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+
+ // A couple of URLs
+ CheckParser(u"camera http://example.com http://example.net"_ns, true, 1,
+ parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
+
+ // A couple of URLs + self
+ CheckParser(u"camera http://example.com 'self' http://example.net"_ns, true,
+ 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
+ ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
+
+ // A couple of URLs but then *
+ CheckParser(u"camera http://example.com 'self' http://example.net *"_ns, true,
+ 1, parsedFeatures);
+ ASSERT_TRUE(parsedFeatures[0].Name().Equals(u"camera"_ns));
+ ASSERT_TRUE(parsedFeatures[0].AllowsAll());
+}
diff --git a/dom/security/featurepolicy/test/gtest/moz.build b/dom/security/featurepolicy/test/gtest/moz.build
new file mode 100644
index 0000000000..e307810ff2
--- /dev/null
+++ b/dom/security/featurepolicy/test/gtest/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+UNIFIED_SOURCES = [
+ "TestFeaturePolicyParser.cpp",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul-gtest"
diff --git a/dom/security/featurepolicy/test/mochitest/empty.html b/dom/security/featurepolicy/test/mochitest/empty.html
new file mode 100644
index 0000000000..64355e7d19
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/empty.html
@@ -0,0 +1 @@
+Nothing here
diff --git a/dom/security/featurepolicy/test/mochitest/mochitest.toml b/dom/security/featurepolicy/test/mochitest/mochitest.toml
new file mode 100644
index 0000000000..c621331596
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/mochitest.toml
@@ -0,0 +1,14 @@
+[DEFAULT]
+prefs = [
+ "dom.security.featurePolicy.header.enabled=true",
+ "dom.security.featurePolicy.webidl.enabled=true",
+]
+support-files = [
+ "empty.html",
+ "test_parser.html^headers^",
+]
+
+["test_featureList.html"]
+
+["test_parser.html"]
+fail-if = ["xorigin"]
diff --git a/dom/security/featurepolicy/test/mochitest/test_featureList.html b/dom/security/featurepolicy/test/mochitest/test_featureList.html
new file mode 100644
index 0000000000..8a518da653
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/test_featureList.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test feature policy - list</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe src="empty.html" id="ifr"></iframe>
+<script type="text/javascript">
+
+let supportedFeatures = [
+ "autoplay",
+ "camera",
+ "encrypted-media",
+ "fullscreen",
+ "gamepad",
+ "geolocation",
+ "microphone",
+ "midi",
+ "payment",
+ "publickey-credentials-create",
+ "publickey-credentials-get",
+ "storage-access",
+ "display-capture",
+ "document-domain",
+ "speaker-selection",
+ "vr",
+ "web-share",
+ "screen-wake-lock",
+];
+
+function checkFeatures(features) {
+ features.forEach(feature => {
+ ok(supportedFeatures.includes(feature), "Feature: " + feature);
+ });
+}
+
+ok("featurePolicy" in document, "We have document.featurePolicy");
+checkFeatures(document.featurePolicy.features());
+
+let ifr = document.getElementById("ifr");
+ok("featurePolicy" in ifr, "We have HTMLIFrameElement.featurePolicy");
+checkFeatures(ifr.featurePolicy.features());
+
+</script>
+</body>
+</html>
diff --git a/dom/security/featurepolicy/test/mochitest/test_parser.html b/dom/security/featurepolicy/test/mochitest/test_parser.html
new file mode 100644
index 0000000000..a8322f6e7d
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/test_parser.html
@@ -0,0 +1,418 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test feature policy - parsing</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe src="empty.html" id="ifr"></iframe>
+<iframe src="https://example.org/tests/dom/security/featurePolicy/test/mochitest/empty.html" id="cross_ifr"></iframe>
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+const CROSS_ORIGIN = "https://example.org";
+
+function test_document() {
+ info("Checking document.featurePolicy");
+ ok("featurePolicy" in document, "We have document.featurePolicy");
+
+ ok(!document.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!document.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(document.featurePolicy.allowsFeature("camera"), "Camera is allowed for self");
+ ok(document.featurePolicy.allowsFeature("camera", "https://foo.bar"), "Camera is always allowed");
+ let allowed = document.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 1, "Only 1 entry in allowlist for camera");
+ is(allowed[0], "*", "allowlist is *");
+
+ ok(document.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ ok(document.featurePolicy.allowsFeature("geolocation", location.origin), "Geolocation is allowed for self");
+ ok(!document.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = document.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ is(allowed[0], location.origin, "allowlist is self");
+
+ ok(!document.featurePolicy.allowsFeature("microphone"), "Microphone is disabled for self");
+ ok(!document.featurePolicy.allowsFeature("microphone", location.origin), "Microphone is disabled for self");
+ ok(!document.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(document.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is allowed for example.com");
+ ok(document.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is allowed for example.org");
+ allowed = document.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 0, "No allowlist for microphone");
+
+ ok(!document.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!document.featurePolicy.allowsFeature("vr", location.origin), "Vibrate is disabled for self");
+ ok(!document.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = document.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ allowed = document.featurePolicy.allowedFeatures();
+ // microphone is disabled for this origin, vr is disabled everywhere.
+ let camera = false;
+ let geolocation = false;
+ allowed.forEach(a => {
+ if (a == "camera") camera = true;
+ if (a == "geolocation") geolocation = true;
+ });
+
+ ok(camera, "Camera is always allowed");
+ ok(geolocation, "Geolocation is allowed only for self");
+
+ next();
+}
+
+function test_iframe_without_allow() {
+ info("Checking HTMLIFrameElement.featurePolicy");
+ let ifr = document.getElementById("ifr");
+ ok("featurePolicy" in ifr, "HTMLIFrameElement.featurePolicy exists");
+
+ ok(!ifr.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!ifr.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(ifr.featurePolicy.allowsFeature("camera"), "Camera is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("camera", location.origin), "Camera is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("camera", "https://foo.bar"), "Camera is not allowed for a random URL");
+ let allowed = ifr.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 1, "Only 1 entry in allowlist for camera");
+ is(allowed[0], location.origin, "allowlist is 'self'");
+
+ ok(ifr.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("geolocation", location.origin), "Geolocation is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ is(allowed[0], location.origin, "allowlist is '*'");
+
+ ok(!ifr.featurePolicy.allowsFeature("microphone"), "Microphone is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", location.origin), "Microphone is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is disabled for example.org");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 0, "No allowlist for microphone");
+
+ ok(!ifr.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", location.origin), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ ok(ifr.featurePolicy.allowedFeatures().includes("camera"), "Camera is allowed");
+ ok(ifr.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is allowed");
+ // microphone is disabled for this origin
+ ok(!ifr.featurePolicy.allowedFeatures().includes("microphone"), "microphone is not allowed");
+ // vr is disabled everywhere.
+ ok(!ifr.featurePolicy.allowedFeatures().includes("vr"), "VR is not allowed");
+
+ next();
+}
+
+function test_iframe_with_allow() {
+ info("Checking HTMLIFrameElement.featurePolicy");
+ let ifr = document.getElementById("ifr");
+ ok("featurePolicy" in ifr, "HTMLIFrameElement.featurePolicy exists");
+
+ ifr.setAttribute("allow", "camera 'none'");
+
+ ok(!ifr.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!ifr.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(!ifr.featurePolicy.allowsFeature("camera"), "Camera is not allowed");
+ let allowed = ifr.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 0, "Camera has an empty allowlist");
+
+ ok(ifr.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("geolocation", location.origin), "Geolocation is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ is(allowed[0], location.origin, "allowlist is '*'");
+
+ ok(!ifr.featurePolicy.allowsFeature("microphone"), "Microphone is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", location.origin), "Microphone is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is disabled for example.org");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 0, "No allowlist for microphone");
+
+ ok(!ifr.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", location.origin), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ ok(ifr.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is allowed only for self");
+
+ next();
+}
+
+function test_iframe_contentDocument() {
+ info("Checking iframe document.featurePolicy");
+
+ let ifr = document.createElement("iframe");
+ ifr.setAttribute("src", "empty.html");
+ ifr.onload = function() {
+ ok("featurePolicy" in ifr.contentDocument, "We have ifr.contentDocument.featurePolicy");
+
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(ifr.contentDocument.featurePolicy.allowsFeature("camera"), "Camera is allowed for self");
+ ok(ifr.contentDocument.featurePolicy.allowsFeature("camera", location.origin), "Camera is allowed for self");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("camera", "https://foo.bar"), "Camera is allowed for self");
+ let allowed = ifr.contentDocument.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 1, "Only 1 entry in allowlist for camera");
+ is(allowed[0], location.origin, "allowlist is 'self'");
+
+ ok(ifr.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("geolocation", location.origin), "Geolocation is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ is(allowed[0], location.origin, "allowlist is '*'");
+
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("microphone"), "Microphone is disabled for self");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("microphone", location.origin), "Microphone is disabled for self");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is allowed for example.com");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is allowed for example.org");
+ allowed = ifr.contentDocument.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 0, "No allowlist for microphone");
+
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("vr", location.origin), "Vibrate is disabled for self");
+ ok(!ifr.contentDocument.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = ifr.contentDocument.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ ok(ifr.contentDocument.featurePolicy.allowedFeatures().includes("camera"), "Camera is allowed");
+ ok(ifr.contentDocument.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is allowed");
+ // microphone is disabled for this origin
+ ok(!ifr.contentDocument.featurePolicy.allowedFeatures().includes("microphone"), "Microphone is not allowed");
+ // vr is disabled everywhere.
+ ok(!ifr.contentDocument.featurePolicy.allowedFeatures().includes("vr"), "VR is not allowed");
+
+ next();
+ };
+ document.body.appendChild(ifr);
+}
+
+function test_cross_iframe_without_allow() {
+ info("Checking cross HTMLIFrameElement.featurePolicy no allow");
+ let ifr = document.getElementById("cross_ifr");
+ ok("featurePolicy" in ifr, "HTMLIFrameElement.featurePolicy exists");
+
+ ok(!ifr.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!ifr.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(ifr.featurePolicy.allowsFeature("camera"), "Camera is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("camera", CROSS_ORIGIN), "Camera is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("camera", "https://foo.bar"), "Camera is not allowed for a random URL");
+ let allowed = ifr.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 1, "Only 1 entry in allowlist for camera");
+ is(allowed[0], CROSS_ORIGIN, "allowlist is 'self'");
+
+ ok(!ifr.featurePolicy.allowsFeature("geolocation"), "Geolocation is not allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", CROSS_ORIGIN),
+ "Geolocation is not allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 0, "No allowlist for geolocation");
+
+ ok(ifr.featurePolicy.allowsFeature("microphone"), "Microphone is enabled for self");
+ ok(ifr.featurePolicy.allowsFeature("microphone", CROSS_ORIGIN), "Microphone is enabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 1, "Only 1 entry in allowlist for microphone");
+ is(allowed[0], CROSS_ORIGIN, "allowlist is self");
+
+ ok(!ifr.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", CROSS_ORIGIN), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ ok(ifr.featurePolicy.allowedFeatures().includes("camera"), "Camera is allowed");
+ ok(!ifr.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is not allowed");
+ // microphone is enabled for this origin
+ ok(ifr.featurePolicy.allowedFeatures().includes("microphone"), "microphone is allowed");
+ // vr is disabled everywhere.
+ ok(!ifr.featurePolicy.allowedFeatures().includes("vr"), "VR is not allowed");
+
+ next();
+}
+
+function test_cross_iframe_with_allow() {
+ info("Checking cross HTMLIFrameElement.featurePolicy with allow");
+ let ifr = document.getElementById("cross_ifr");
+ ok("featurePolicy" in ifr, "HTMLIFrameElement.featurePolicy exists");
+
+ ifr.setAttribute("allow", "geolocation; camera 'none'");
+
+ ok(!ifr.featurePolicy.allowsFeature("foobar"), "Random feature");
+ ok(!ifr.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ ok(!ifr.featurePolicy.allowsFeature("camera"), "Camera is not allowed");
+ let allowed = ifr.featurePolicy.getAllowlistForFeature("camera");
+ is(allowed.length, 0, "Camera has an empty allowlist");
+
+ ok(ifr.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ ok(ifr.featurePolicy.allowsFeature("geolocation", CROSS_ORIGIN), "Geolocation is allowed for self");
+ ok(!ifr.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("geolocation");
+ is(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ is(allowed[0], CROSS_ORIGIN, "allowlist is '*'");
+
+ ok(ifr.featurePolicy.allowsFeature("microphone"), "Microphone is enabled for self");
+ ok(ifr.featurePolicy.allowsFeature("microphone", CROSS_ORIGIN), "Microphone is enabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ ok(!ifr.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("microphone");
+ is(allowed.length, 1, "Only 1 entry in allowlist for microphone");
+ is(allowed[0], CROSS_ORIGIN, "allowlist is self");
+
+ ok(!ifr.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", CROSS_ORIGIN), "Vibrate is disabled for self");
+ ok(!ifr.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = ifr.featurePolicy.getAllowlistForFeature("vr");
+ is(allowed.length, 0, "No allowlist for vr");
+
+ ok(ifr.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is allowed only for self");
+ // microphone is enabled for this origin
+ ok(ifr.featurePolicy.allowedFeatures().includes("microphone"), "microphone is allowed");
+
+ next();
+}
+
+function test_cross_iframe_contentDocument_no_allow() {
+ info("Checking cross iframe document.featurePolicy no allow");
+
+ let ifr = document.createElement("iframe");
+ ifr.setAttribute("src", "https://example.org/tests/dom/security/featurePolicy/test/mochitest/empty.html");
+ ifr.onload = async function() {
+ await SpecialPowers.spawn(ifr, [], () => {
+ Assert.ok("featurePolicy" in this.content.document, "We have this.content.document.featurePolicy");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("foobar"), "Random feature");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("camera"), "Camera is allowed for self");
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("camera", "https://example.org"), "Camera is allowed for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("camera", "https://foo.bar"), "Camera is not allowed for a random URL");
+ let allowed = this.content.document.featurePolicy.getAllowlistForFeature("camera");
+ Assert.equal(allowed.length, 1, "Only 1 entry in allowlist for camera");
+ Assert.equal(allowed[0], "https://example.org", "allowlist is 'self'");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("geolocation"), "Geolocation is not allowed for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("geolocation", "https://example.org"),
+ "Geolocation is not allowed for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("geolocation");
+ Assert.equal(allowed.length, 0, "No allowlist for geolocation");
+
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("microphone"), "Microphone is enabled for self");
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is enabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("microphone");
+ Assert.equal(allowed.length, 1, "Only 1 entry in allowlist for microphone");
+ Assert.equal(allowed[0], "https://example.org", "allowlist is self");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr", "https://example.org"), "Vibrate is disabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("vr");
+ Assert.equal(allowed.length, 0, "No allowlist for vr");
+
+ Assert.ok(this.content.document.featurePolicy.allowedFeatures().includes("camera"), "Camera is allowed");
+ Assert.ok(!this.content.document.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is not allowed");
+ // microphone is enabled for this origin
+ Assert.ok(this.content.document.featurePolicy.allowedFeatures().includes("microphone"), "microphone is allowed");
+ // vr is disabled everywhere.
+ Assert.ok(!this.content.document.featurePolicy.allowedFeatures().includes("vr"), "VR is not allowed");
+ });
+
+ next();
+ };
+ document.body.appendChild(ifr);
+}
+
+function test_cross_iframe_contentDocument_allow() {
+ info("Checking cross iframe document.featurePolicy with allow");
+
+ let ifr = document.createElement("iframe");
+ ifr.setAttribute("src", "https://example.org/tests/dom/security/featurePolicy/test/mochitest/empty.html");
+ ifr.setAttribute("allow", "geolocation; camera 'none'");
+ ifr.onload = async function() {
+ await SpecialPowers.spawn(ifr, [], () => {
+ Assert.ok("featurePolicy" in this.content.document, "We have this.content.document.featurePolicy");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("foobar"), "Random feature");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("foobar", "https://www.something.net"), "Random feature");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("camera"), "Camera is not allowed");
+ let allowed = this.content.document.featurePolicy.getAllowlistForFeature("camera");
+ Assert.equal(allowed.length, 0, "Camera has an empty allowlist");
+
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("geolocation"), "Geolocation is allowed for self");
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("geolocation", "https://example.org"), "Geolocation is allowed for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("geolocation", "https://foo.bar"), "Geolocation is not allowed for any random URL");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("geolocation");
+ Assert.equal(allowed.length, 1, "Only 1 entry in allowlist for geolocation");
+ Assert.equal(allowed[0], "https://example.org", "allowlist is '*'");
+
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("microphone"), "Microphone is enabled for self");
+ Assert.ok(this.content.document.featurePolicy.allowsFeature("microphone", "https://example.org"), "Microphone is enabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("microphone", "https://foo.bar"), "Microphone is disabled for foo.bar");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("microphone", "https://example.com"), "Microphone is disabled for example.com");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("microphone");
+ Assert.equal(allowed.length, 1, "Only 1 entry in allowlist for microphone");
+ Assert.equal(allowed[0], "https://example.org", "allowlist is self");
+
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr"), "Vibrate is disabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr", "https://example.org"), "Vibrate is disabled for self");
+ Assert.ok(!this.content.document.featurePolicy.allowsFeature("vr", "https://foo.bar"), "Vibrate is disabled for foo.bar");
+ allowed = this.content.document.featurePolicy.getAllowlistForFeature("vr");
+ Assert.equal(allowed.length, 0, "No allowlist for vr");
+
+ Assert.ok(this.content.document.featurePolicy.allowedFeatures().includes("geolocation"), "Geolocation is allowed only for self");
+ // microphone is enabled for this origin
+ Assert.ok(this.content.document.featurePolicy.allowedFeatures().includes("microphone"), "microphone is allowed");
+ });
+
+ next();
+ };
+ document.body.appendChild(ifr);
+}
+
+
+var tests = [
+ test_document,
+ test_iframe_without_allow,
+ test_iframe_with_allow,
+ test_iframe_contentDocument,
+ test_cross_iframe_without_allow,
+ test_cross_iframe_with_allow,
+ test_cross_iframe_contentDocument_no_allow,
+ test_cross_iframe_contentDocument_allow
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+next();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/featurepolicy/test/mochitest/test_parser.html^headers^ b/dom/security/featurepolicy/test/mochitest/test_parser.html^headers^
new file mode 100644
index 0000000000..949de013d3
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/test_parser.html^headers^
@@ -0,0 +1 @@
+Feature-Policy: camera *; geolocation 'self'; microphone https://example.com https://example.org; vr 'none'