summaryrefslogtreecommitdiffstats
path: root/dom/security/featurepolicy/FeaturePolicyParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/security/featurepolicy/FeaturePolicyParser.cpp')
-rw-r--r--dom/security/featurepolicy/FeaturePolicyParser.cpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/dom/security/featurepolicy/FeaturePolicyParser.cpp b/dom/security/featurepolicy/FeaturePolicyParser.cpp
new file mode 100644
index 0000000000..8ab95420aa
--- /dev/null
+++ b/dom/security/featurepolicy/FeaturePolicyParser.cpp
@@ -0,0 +1,157 @@
+/* -*- 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 "FeaturePolicyParser.h"
+
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/dom/Feature.h"
+#include "mozilla/dom/FeaturePolicyUtils.h"
+#include "mozilla/dom/PolicyTokenizer.h"
+#include "nsIScriptError.h"
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+
+namespace mozilla::dom {
+
+namespace {
+
+void ReportToConsoleUnsupportedFeature(Document* aDocument,
+ const nsString& aFeatureName) {
+ if (!aDocument) {
+ return;
+ }
+
+ AutoTArray<nsString, 1> params = {aFeatureName};
+
+ nsContentUtils::ReportToConsole(
+ nsIScriptError::warningFlag, "Feature Policy"_ns, aDocument,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "FeaturePolicyUnsupportedFeatureName", params);
+}
+
+void ReportToConsoleInvalidEmptyAllowValue(Document* aDocument,
+ const nsString& aFeatureName) {
+ if (!aDocument) {
+ return;
+ }
+
+ AutoTArray<nsString, 1> params = {aFeatureName};
+
+ nsContentUtils::ReportToConsole(
+ nsIScriptError::warningFlag, "Feature Policy"_ns, aDocument,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "FeaturePolicyInvalidEmptyAllowValue", params);
+}
+
+void ReportToConsoleInvalidAllowValue(Document* aDocument,
+ const nsString& aValue) {
+ if (!aDocument) {
+ return;
+ }
+
+ AutoTArray<nsString, 1> params = {aValue};
+
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ "Feature Policy"_ns, aDocument,
+ nsContentUtils::eSECURITY_PROPERTIES,
+ "FeaturePolicyInvalidAllowValue", params);
+}
+
+} // namespace
+
+/* static */
+bool FeaturePolicyParser::ParseString(const nsAString& aPolicy,
+ Document* aDocument,
+ nsIPrincipal* aSelfOrigin,
+ nsIPrincipal* aSrcOrigin,
+ nsTArray<Feature>& aParsedFeatures) {
+ MOZ_ASSERT(aSelfOrigin);
+
+ nsTArray<CopyableTArray<nsString>> tokens;
+ PolicyTokenizer::tokenizePolicy(aPolicy, tokens);
+
+ nsTArray<Feature> parsedFeatures;
+
+ for (const nsTArray<nsString>& featureTokens : tokens) {
+ if (featureTokens.IsEmpty()) {
+ continue;
+ }
+
+ if (!FeaturePolicyUtils::IsSupportedFeature(featureTokens[0])) {
+ ReportToConsoleUnsupportedFeature(aDocument, featureTokens[0]);
+ continue;
+ }
+
+ Feature feature(featureTokens[0]);
+
+ if (featureTokens.Length() == 1) {
+ if (aSrcOrigin) {
+ feature.AppendToAllowList(aSrcOrigin);
+ } else {
+ ReportToConsoleInvalidEmptyAllowValue(aDocument, featureTokens[0]);
+ continue;
+ }
+ } else {
+ // we gotta start at 1 here
+ for (uint32_t i = 1; i < featureTokens.Length(); ++i) {
+ const nsString& curVal = featureTokens[i];
+ if (curVal.LowerCaseEqualsASCII("'none'")) {
+ feature.SetAllowsNone();
+ break;
+ }
+
+ if (curVal.EqualsLiteral("*")) {
+ feature.SetAllowsAll();
+ break;
+ }
+
+ if (curVal.LowerCaseEqualsASCII("'self'")) {
+ feature.AppendToAllowList(aSelfOrigin);
+ continue;
+ }
+
+ if (aSrcOrigin && curVal.LowerCaseEqualsASCII("'src'")) {
+ feature.AppendToAllowList(aSrcOrigin);
+ continue;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), curVal);
+ if (NS_FAILED(rv)) {
+ ReportToConsoleInvalidAllowValue(aDocument, curVal);
+ continue;
+ }
+
+ nsCOMPtr<nsIPrincipal> origin = BasePrincipal::CreateContentPrincipal(
+ uri, BasePrincipal::Cast(aSelfOrigin)->OriginAttributesRef());
+ if (NS_WARN_IF(!origin)) {
+ ReportToConsoleInvalidAllowValue(aDocument, curVal);
+ continue;
+ }
+
+ feature.AppendToAllowList(origin);
+ }
+ }
+
+ // No duplicate!
+ bool found = false;
+ for (const Feature& parsedFeature : parsedFeatures) {
+ if (parsedFeature.Name() == feature.Name()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ parsedFeatures.AppendElement(feature);
+ }
+ }
+
+ aParsedFeatures = std::move(parsedFeatures);
+ return true;
+}
+
+} // namespace mozilla::dom