Bug 1492036 - Reporting API - part 6 - FeaturePolicy, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 14 Nov 2018 20:02:33 +0100
changeset 446335 ed3b5f933b97dc43e40fa153a03c4a55e830e7cf
parent 446334 3e311bf1af407110e07215872044d8451347ff8f
child 446336 6119216d9038e35089b6d5a23a3d9a0deb1b8416
push id109862
push useramarchesini@mozilla.com
push dateWed, 14 Nov 2018 19:03:36 +0000
treeherdermozilla-inbound@2751ee1bdac6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1492036
milestone65.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 1492036 - Reporting API - part 6 - FeaturePolicy, r=smaug
dom/base/DOMPrefsInternal.h
dom/reporting/FeaturePolicyViolationReportBody.cpp
dom/reporting/FeaturePolicyViolationReportBody.h
dom/reporting/moz.build
dom/security/featurepolicy/FeaturePolicyUtils.cpp
dom/security/featurepolicy/FeaturePolicyUtils.h
dom/webidl/FeaturePolicy.webidl
modules/libpref/init/StaticPrefList.h
xpcom/ds/StaticAtoms.py
--- a/dom/base/DOMPrefsInternal.h
+++ b/dom/base/DOMPrefsInternal.h
@@ -25,9 +25,10 @@ DOM_WEBIDL_PREF(dom_push_enabled)
 DOM_WEBIDL_PREF(gfx_offscreencanvas_enabled)
 DOM_WEBIDL_PREF(dom_webkitBlink_dirPicker_enabled)
 DOM_WEBIDL_PREF(dom_netinfo_enabled)
 DOM_WEBIDL_PREF(dom_fetchObserver_enabled)
 DOM_WEBIDL_PREF(dom_enable_performance_observer)
 DOM_WEBIDL_PREF(dom_performance_enable_scheduler_timing)
 DOM_WEBIDL_PREF(dom_reporting_enabled)
 DOM_WEBIDL_PREF(dom_reporting_testing_enabled)
+DOM_WEBIDL_PREF(dom_reporting_featurePolicy_enabled)
 DOM_WEBIDL_PREF(javascript_options_streams)
new file mode 100644
--- /dev/null
+++ b/dom/reporting/FeaturePolicyViolationReportBody.cpp
@@ -0,0 +1,66 @@
+/* -*- 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 "mozilla/dom/FeaturePolicyViolationReportBody.h"
+#include "mozilla/dom/FeaturePolicyBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+FeaturePolicyViolationReportBody::FeaturePolicyViolationReportBody(nsPIDOMWindowInner* aWindow,
+                                                                   const nsAString& aFeatureId,
+                                                                   const nsAString& aSourceFile,
+                                                                   const Nullable<int32_t>& aLineNumber,
+                                                                   const Nullable<int32_t>& aColumnNumber,
+                                                                   const nsAString& aDisposition)
+  : ReportBody(aWindow)
+  , mFeatureId(aFeatureId)
+  , mSourceFile(aSourceFile)
+  , mLineNumber(aLineNumber)
+  , mColumnNumber(aColumnNumber)
+  , mDisposition(aDisposition)
+{}
+
+FeaturePolicyViolationReportBody::~FeaturePolicyViolationReportBody() = default;
+
+JSObject*
+FeaturePolicyViolationReportBody::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return FeaturePolicyViolationReportBody_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FeaturePolicyViolationReportBody::GetFeatureId(nsAString& aFeatureId) const
+{
+  aFeatureId = mFeatureId;
+}
+
+void
+FeaturePolicyViolationReportBody::GetSourceFile(nsAString& aSourceFile) const
+{
+  aSourceFile = mSourceFile;
+}
+
+Nullable<int32_t>
+FeaturePolicyViolationReportBody::GetLineNumber() const
+{
+  return mLineNumber;
+}
+
+Nullable<int32_t>
+FeaturePolicyViolationReportBody::GetColumnNumber() const
+{
+  return mColumnNumber;
+}
+
+void
+FeaturePolicyViolationReportBody::GetDisposition(nsAString& aDisposition) const
+{
+  aDisposition = mDisposition;
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/reporting/FeaturePolicyViolationReportBody.h
@@ -0,0 +1,57 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_FeaturePolicyViolationReportBody_h
+#define mozilla_dom_FeaturePolicyViolationReportBody_h
+
+#include "mozilla/dom/ReportBody.h"
+#include "mozilla/dom/Date.h"
+
+namespace mozilla {
+namespace dom {
+
+class FeaturePolicyViolationReportBody final : public ReportBody
+{
+public:
+  FeaturePolicyViolationReportBody(nsPIDOMWindowInner* aWindow,
+                                   const nsAString& aFeatureId,
+                                   const nsAString& aSourceFile,
+                                   const Nullable<int32_t>& aLineNumber,
+                                   const Nullable<int32_t>& aColumnNumber,
+                                   const nsAString& aDisposition);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  void
+  GetFeatureId(nsAString& aFeatureId) const;
+
+  void
+  GetSourceFile(nsAString& aSourceFile) const;
+
+  Nullable<int32_t>
+  GetLineNumber() const;
+
+  Nullable<int32_t>
+  GetColumnNumber() const;
+
+  void
+  GetDisposition(nsAString& aDisposition) const;
+
+private:
+  ~FeaturePolicyViolationReportBody();
+
+  const nsString mFeatureId;
+  const nsString mSourceFile;
+  const Nullable<int32_t> mLineNumber;
+  const Nullable<int32_t> mColumnNumber;
+  const nsString mDisposition;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_FeaturePolicyViolationReportBody_h
--- a/dom/reporting/moz.build
+++ b/dom/reporting/moz.build
@@ -1,25 +1,27 @@
 # -*- 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/.
 
 EXPORTS.mozilla.dom = [
     'DeprecationReportBody.h',
+    'FeaturePolicyViolationReportBody.h',
     'Report.h',
     'ReportBody.h',
     'ReportingObserver.h',
     'ReportingUtils.h',
     'TestingDeprecatedInterface.h',
 ]
 
 UNIFIED_SOURCES += [
     'DeprecationReportBody.cpp',
+    'FeaturePolicyViolationReportBody.cpp',
     'Report.cpp',
     'ReportBody.cpp',
     'ReportingObserver.cpp',
     'ReportingUtils.cpp',
     'TestingDeprecatedInterface.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/security/featurepolicy/FeaturePolicyUtils.cpp
+++ b/dom/security/featurepolicy/FeaturePolicyUtils.cpp
@@ -1,18 +1,21 @@
 /* -*- 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 "FeaturePolicyUtils.h"
 #include "mozilla/dom/FeaturePolicy.h"
+#include "mozilla/dom/FeaturePolicyViolationReportBody.h"
+#include "mozilla/dom/ReportingUtils.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsIDocument.h"
+#include "nsIURIFixup.h"
 
 namespace mozilla {
 namespace dom {
 
 struct FeatureMap {
   const char* mFeatureName;
   FeaturePolicyUtils::FeaturePolicyValue mDefaultAllowList;
 };
@@ -82,13 +85,78 @@ FeaturePolicyUtils::IsFeatureAllowed(nsI
 
   if (!aDocument->IsHTMLDocument()) {
     return true;
   }
 
   FeaturePolicy* policy = aDocument->Policy();
   MOZ_ASSERT(policy);
 
-  return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin());
+  if (policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin())) {
+    return true;
+  }
+
+  ReportViolation(aDocument, aFeatureName);
+  return false;
+}
+
+/* static */ void
+FeaturePolicyUtils::ReportViolation(nsIDocument* aDocument,
+                                    const nsAString& aFeatureName)
+{
+  MOZ_ASSERT(aDocument);
+
+  nsCOMPtr<nsIURI> uri = aDocument->GetDocumentURI();
+  if (NS_WARN_IF(!uri)) {
+    return;
+  }
+
+  // Strip the URL of any possible username/password and make it ready to be
+  // presented in the UI.
+  nsCOMPtr<nsIURIFixup> urifixup = services::GetURIFixup();
+  if (NS_WARN_IF(!urifixup)) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> exposableURI;
+  nsresult rv = urifixup->CreateExposableURI(uri, getter_AddRefs(exposableURI));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  nsAutoCString spec;
+  rv = exposableURI->GetSpec(spec);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  if (NS_WARN_IF(!cx)) {
+    return;
+  }
+
+  nsAutoCString fileName;
+  Nullable<int32_t> lineNumber;
+  Nullable<int32_t> columnNumber;
+  uint32_t line = 0;
+  uint32_t column = 0;
+  if (nsJSUtils::GetCallingLocation(cx, fileName, &line, &column)) {
+    lineNumber.SetValue(static_cast<int32_t>(line));
+    columnNumber.SetValue(static_cast<int32_t>(column));
+  }
+
+  nsPIDOMWindowInner* window = aDocument->GetInnerWindow();
+  if (NS_WARN_IF(!window)) {
+    return;
+  }
+
+  RefPtr<FeaturePolicyViolationReportBody> body =
+    new FeaturePolicyViolationReportBody(window, aFeatureName,
+                                         NS_ConvertUTF8toUTF16(fileName),
+                                         lineNumber, columnNumber,
+                                         NS_LITERAL_STRING("enforce"));
+
+  ReportingUtils::Report(window,
+                         nsGkAtoms::featurePolicyViolation,
+                         NS_ConvertUTF8toUTF16(spec), body);
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/security/featurepolicy/FeaturePolicyUtils.h
+++ b/dom/security/featurepolicy/FeaturePolicyUtils.h
@@ -43,14 +43,19 @@ public:
   // Runs aCallback for each known feature policy, with the feature name as
   // argument.
   static void
   ForEachFeature(const std::function<void(const char*)>& aCallback);
 
   // Returns the default policy value for aFeatureName.
   static FeaturePolicyValue
   DefaultAllowListFeature(const nsAString& aFeatureName);
+
+private:
+  static void
+  ReportViolation(nsIDocument* aDocument,
+                  const nsAString& aFeatureName);
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_FeaturePolicyUtils_h
--- a/dom/webidl/FeaturePolicy.webidl
+++ b/dom/webidl/FeaturePolicy.webidl
@@ -8,8 +8,17 @@
  */
 
 [NoInterfaceObject]
 interface Policy {
   boolean allowsFeature(DOMString feature, optional DOMString origin);
   sequence<DOMString> allowedFeatures();
   sequence<DOMString> getAllowlistForFeature(DOMString feature);
 };
+
+[Func="mozilla::dom::DOMPrefs::dom_reporting_featurePolicy_enabled"]
+interface FeaturePolicyViolationReportBody : ReportBody {
+  readonly attribute DOMString featureId;
+  readonly attribute DOMString? sourceFile;
+  readonly attribute long? lineNumber;
+  readonly attribute long? columnNumber;
+  readonly attribute DOMString disposition;
+};
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1791,13 +1791,19 @@ VARCACHE_PREF(
 )
 
 VARCACHE_PREF(
   "dom.reporting.testing.enabled",
    dom_reporting_testing_enabled,
   RelaxedAtomicBool, false
 )
 
+VARCACHE_PREF(
+  "dom.reporting.featurePolicy.enabled",
+   dom_reporting_featurePolicy_enabled,
+  RelaxedAtomicBool, false
+)
+
 //---------------------------------------------------------------------------
 // End of prefs
 //---------------------------------------------------------------------------
 
 // clang-format on
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -400,16 +400,17 @@ STATIC_ATOMS = [
     Atom("events", "events"),
     Atom("excludeResultPrefixes", "exclude-result-prefixes"),
     Atom("extends", "extends"),
     Atom("extensionElementPrefixes", "extension-element-prefixes"),
     Atom("face", "face"),
     Atom("fallback", "fallback"),
     Atom("_false", "false"),
     Atom("farthest", "farthest"),
+    Atom("featurePolicyViolation", "feature-policy-violation"),
     Atom("field", "field"),
     Atom("fieldset", "fieldset"),
     Atom("file", "file"),
     Atom("figcaption", "figcaption"),
     Atom("figure", "figure"),
     Atom("findbar", "findbar"),
     Atom("fixed", "fixed"),
     Atom("flags", "flags"),